サービス層の脆弱なテストを避ける

目次

テスト] 4. ** まとめ

1概要

アプリケーションのサービス層をテストするには多くの方法があります。この記事の目的は、データベースとのやり取りを完全に模擬することによって、このレイヤーを単独で単体テストする方法の1つを示すことです。

この例では、依存性注入にhttp://spring.io/[Spring]、JUnit、http://code.google.com/p/hamcrest/[Hamcrest]、http://code.google.com/を使用しますp/mockito/[Mockito]テスト用ですが、テクノロジはさまざまです。

2レイヤー

一般的なJava Webアプリケーションは、DAL/DAO層の上にサービス層を持ち、それが生の永続層を呼び出します。

1.1. サービス層

@Service
public class FooService implements IFooService{

   @Autowired
   IFooDAO dao;

   @Override
   public Long create( Foo entity ){
      return this.dao.create( entity );
   }

}

1.2. DAL/DAOレイヤー

@Repository
public class FooDAO extends HibernateDaoSupport implements IFooDAO{

   public Long create( Foo entity ){
      Preconditions.checkNotNull( entity );

      return (Long) this.getHibernateTemplate().save( entity );
   }

}

3単体テストの動機とぼやけ

サービスをユニットテストするとき、標準の unit は通常service class です。テストはその下の層、この場合はDAO/DAL層を模擬し、その上の相互作用を検証します。データベースとのやりとり(この例では HibernateTemplate )を模擬し、それとのやりとりを検証することで、DAO層についてもまったく同じです。

これは有効な方法ですが、脆弱なテストにつながります。レイヤーを追加または削除すると、ほとんどの場合、テスト全体を書き直すことになります。これは、テストがレイヤの正確な構造に依存しているために発生します。それを変更すると、テストが変更されます。

このような柔軟性のなさを避けるために、ユニットの定義を変更することでユニットテストの範囲を広げることができます。サービス層から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() ) );
   }

}

今度はテストはただ1つの責任に焦点を合わせます - 作成が引き起こされるとき、作成はデータベースに達しますか。

最後のテストでは、Mockito検証構文を使用して、 save メソッドがHibernateテンプレートで呼び出されたことを確認し、プロセス内の引数を取得して、確認できるようにします。エンティティを作成する 責任 は、状態をチェックする必要なしに、このインタラクションテストによって検証されます - テストは、休止状態の保存ロジックが意図したとおりに機能していることを信頼します。もちろん、それもテストする必要がありますが、それは別の責任であり、別の種類のテストです。

4結論

このテクニックは常により集中的なテストにつながります。テストが失敗する唯一の理由は、テスト中の 責任 が壊れているためです。