标签:脆弱 Service entity instance 测试 Foo public
1、简述
有很多方法可以测试Service层。本文的目标是展示一种隔离的测试方式:将于数据库交互的整个逻辑都Mock掉。
示例使用了Spring作为依赖注入、JUnit、Hamcrest、Mockito。
2、分层
典型的Java web应用都在DAO/DAL层之上有一个服务层,DAO/DAL层负责调用原生的持久层逻辑。
Service层
@Service
public class FooService implements IFooService{
@Autowired
IFooDAO dao;
@Override
public Long create( Foo entity ){
return this.dao.create( entity );
}
}
|
DAO/DAL层
@Repository
public class FooDAO extends HibernateDaoSupport implements IFooDAO{
public Long create( Foo entity ){
Preconditions.checkNotNull( entity );
return (Long) this.getHibernateTemplate().save( entity );
}
}
|
3、单元测试的动机和关注点
当单元测试的对象是一个服务的时候,“单元”就是Service类,测试需要模拟Service其下的层,这里就是模拟DAO/DAL层,并验证与之的交互操作。
同样地,对DAO/DAL层的单元测试来说,要模拟掉数据库层(本例中就是HibernateTemplate),并验证相关交互操作。
这个方法是 有效的,但是这样的测试是脆弱的。增加或移除一层的话,就需要完全重写测试。因为测试依赖了层的具体结构,层的变化就意味着测试的变化。
为了避免这种不灵活,我们通过延展“单元”的定义从而扩展单元测试的范围。我们可以把Service层通过DAO和其他方式穿透到持久层的操作看做一个“单元”。单元测试就针对Service层的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() ) );
}
}
|
现在测试只关注Service类的一个职责:当创建被触发,相关操作是否传递到了数据库。
例子里面用Mockito框架的验证语法来检查HiebernateTemplate的save方法是否被调用。测试信任hibernate的保存逻辑,因此创建实体的职责只需要像这样验证save方法是否被调用。
当然保存逻辑也需要被测试,但是这是其他测试的范畴。
4、结论
这种方式会产出更多具有弹性和灵活性的测试。测试失败唯一的原因就是被测试逻辑之下的职责失败了。比如HibernateTemplate的save方法。
标签:脆弱,
Service,
entity,
instance,
测试,
Foo,
public
From: https://blog.51cto.com/u_11326739/6787341