侧边栏壁纸
博主头像
Devlive 开源社区博主等级

行动起来,活在当下

  • 累计撰写 122 篇文章
  • 累计创建 32 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

避免对Service层进行脆性测试

我是管理员哦
2024-02-26 / 0 评论 / 0 点赞 / 8 阅读 / 2847 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2024-02-26,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

案例概述

有许多方法可以测试应用程序的Service层。本文的目标是通过模拟完全与数据库的交互来展示单独测试该层的一种方法。

这个例子将使用Spring进行依赖注入,JUnit,HamcrestMockito进行测试,但技术可能会有所不同。

案例分层

典型的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保存逻辑并预期工作。当然,这也需要进行测试,但这是另一种单元和另一种类型的测试。

案例结论

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

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区