事例概述

有许多办法能够测验应用程序的Service层。本文的方针是经过模仿彻底与数据库的交互来展现独自测验该层的一种办法。

这个例子将运用Spring进行依赖注入,JUnit,Hamcrest和Mockito进行测验,但技术可能会有所不同。

事例分层

典型的Java Web应用程序将在DAL/DAO层之上具有服务层,该层又将调用原始持久层。

Service层

@Service
public class FooService implements IFooService{
   @Autowired
   IFooDAO dao;
   @Override
   public Long create( Foo entity ){
      return this.dao.create( entity );
   }
}

DAL/DAO层

@Repository
public class FooDAO extends HibernateDaoSupport implements IFooDAO{
   public Long create( Foo entity ){
      Preconditions.checkNotNull( entity );
      return (Long) this.getHibernateTemplate().save( entity );
   }
}

含糊的单元测验和动机

当咱们进行测验服务时,规范测验通常是服务类。测验将模仿下面的方式 – 在这种情况下DAO/DAL层验证与其上面的交互。DAO层做同样的工作 – 模仿与数据库的交互(本例运用HibernateTemplate)并验证。

这是一种有用的办法,但它会导致脆性测验 – 增加或删去图层几乎总是意味着彻底重写测验。产生这种情况是因为测验依赖于层的确切结构,而且对此的更改意味着对测验的更改。

为了防止僵化,咱们能够经过更改单元的定义来扩展单元测验的规模 – 咱们能够将持久操作视为一个单元,从Service层到DAO和全天持久性 – 不论是什么。现在,单元测验将运用服务层的API并将进行持久性模仿 – 在这种情况下,HibernateTemplate示例:

public class FooServiceUnitTest{
   FooService instance;
   private HibernateTemplate hibernateTemplateMock;
   @Before
   public void before(){
      this.instance = new FooService();
      this.instance.dao = new FooDAO();
      this.hibernateTemplateMock = mock( HibernateTemplate.class );
      this.instance.dao.setHibernateTemplate( this.hibernateTemplateMock );
   }
   @Test
   public void whenCreateIsTriggered_thenNoException(){
      // When
      this.instance.create( new Foo( "testName" ) );
   }
   @Test( expected = NullPointerException.class )
   public void whenCreateIsTriggeredForNullEntity_thenException(){
      // When
      this.instance.create( null );
   }
   @Test
   public void whenCreateIsTriggered_thenEntityIsCreated(){
      // When
      Foo entity = new Foo( "testName" );
      this.instance.create( entity );
      // Then
      ArgumentCaptor< Foo > argument = ArgumentCaptor.forClass( Foo.class );
      verify( this.hibernateTemplateMock ).save( argument.capture() );
      assertThat( entity, is( argument.getValue() ) );
   }
}

现在,测验只关注单元 – 当触发创立时,创立是否会到达数据库?

最后一个测验运用Mockito验证语法来查看是否已在hibernate模板上调用save办法,捕获过程中的参数以便也能够查看它。经过此交互测验验证创立实体的职责,而无需查看任何状态 – 测验信任hibernate保存逻辑并预期工作。当然,这也需要进行测验,但这是另一种单元和另一种类型的测验。

事例结论

这种技术总是会呈现更会集的测验,这使得它们更具弹性和灵活性。测验失败的唯一原因是因为测验中的职责被打破了。