2013-03-15 7 views
17

私のプロジェクトでは、単体テストの実行に問題があります。 1つの問題は、統合テストを行うだけで書込みがはるかに高速であり、コンポーネントが実際に一緒に機能することもテストすることです。ユニットの斬新な「アルゴリズム」をテストする方がずっと簡単です。単体テストのサービスクラスは間違っていて役に立たないと感じます。春データ:サービスレイヤユニットテスト

私はmockitoを使用してバネデータリポジトリ(したがってDBアクセス)を模擬しています。問題は、メソッド呼び出しgetByIdでエンティティAを返すように嘲笑されたリポジトリに指示すれば、明らかにそれを返し、サービスもそれを返します。はい、サービスはいくつか余分なものを行いますが、ロード・レイジー・コレクション(休止状態からのもの)のような非常に小さなものです。明らかに、単体テストでは遅延コレクション(プロキシ)がありません。

例:

@Test 
public void testGetById() { 
    System.out.println("getById"); 
    TestCompound expResult = new TestCompound(id, "Test Compound", "9999-99-9", null, null, null); 

    TestCompoundRepository mockedRepository = mock(TestCompoundRepository.class); 
    when(mockedRepository.findOne(id)).thenReturn(expResult); 

    ReflectionTestUtils.setField(testCompoundService, "testCompoundRepository", 
      mockedRepository, TestCompoundRepository.class); 

    TestCompound result = testCompoundService.getById(id); 
    assertEquals(expResult, result); 
} 

万歳、残りは成功します。驚いた!実際にはない。

私が間違っていることを説明できる人がいますか?それとも、そのようなテストのポイントは何ですか? expResultを返すように指示してから、返されます。ワオ。驚いた!私のサービスではなく、私がテストしているような気分です。

編集:いくつかの愚かなエラーだった場合、私は見

唯一の利点は、セットがnullまたは愚かな何か似て値を返すことが不要なラインを残すように起こります。そのような場合は単体テストに捕らえられます。それでも「報酬努力」の比率は悪いようですか?

+0

私の答えに関するその他の質問や質問がある場合は、あなたの思考の列車であなたの権利を教えてください。 –

+0

サービスにデータベースにアクセスする以外の機能を備えているサービスは、テストする必要があります。単純なCRUD操作は、DB統合レイヤーでテストするだけです。あなたの 'findById'サービスメソッドがデータベース' findById'メソッドを呼び出していた場合、同じDB /テーブル/リポジトリにはない情報で結果を強化します - ユーザーレコードの例には、逆IPルックアップ - それはサービスレベルでテストするのが理にかなっています。しかし、*すべてを模倣することは、あなたのテストと模擬フレームワークを単体テストすることです。 –

答えて

8

Springデータリポジトリのテストが好きな理由の1つは、JPAマッピングを正しく定義したことをテストすることです。これらのテストでは、私は実際のリポジトリをJunitテストに自動配線してテストを実行できるように、実際にコンテナをブートストラップするSpring Testフレームワークを使用しています。

私は、リポジトリを嘲笑することはかなり役に立たないと思っています。 Springを使用しているので、Springテストフレームワークを利用して、より多くの単体テストベースの方法でH2などの組み込みデータベースに対して実行できる、またはOracleやMySqlなどの実際のデータベース実装で、リポジトリに対して実際のテストを実行することをお勧めします。より多くの統合テストを行います。 (これらを開発データベースのコピーに対して実行する)これらのテストでは、JPAマッピングやデータベース内の不適切なカスケード設定などのその他の項目の不具合が明らかになるでしょう。

ここにはGitHubに関する私のテストのexampleがあります。フレームワークが実際にリポジトリをテストにどのようにautowireするかに注目してください。リポジトリには、Springテストフレームワークを設定する方法の例も含まれています。これについては、blog postで説明しました。

結論として、リポジトリのモックを使って議論したリポジトリをテストすることの利点があるとは思いません。

私が追加したい追加のメモは、テスト中の実際のクラスで実際に使用することを意図したものではないということです。それらの使用は、テスト対象のクラスに必要な依存性を提供するためのものです。

+0

はい、私は、SpringJUnitTestRunnerと実際のリポジトリを使用して完全な統合テストを行っています。ここで私は内部的にリポジトリを使用するサービスを単体テストしようとしています。私のプロジェクトはpostgresqlを必要とするため、メモリ内のデータベースは動作しません。しかし、上記の単体テスト・テストが多かれ少なかれ無益であることに同意することができますか? –

+0

@beginner_はい私はそれにポイントが表示されません。 –

+0

この回答をもう一度読んだ後、私はあなたが私を誤解したと思います。私はリポジトリ自体ではなくリポジトリを使用するサービスをテストしているので、それを嘲笑しています。 –

1

あなたは正確です。それは明らかにユニットテストです。そして、それは決して失敗することはありません(だから無駄です)。 JPAリポジトリデータベース(例えば、メモリ内にH2)でテストするための統合テストが必要だと思います。

サービス(それらのインターフェイス)をテストする方が良いです。しばらくしてからストレージを変更する場合(たとえばMongo)、サービステストを使用して以前と同じようにすべての作業を確実に行うことができます。

しばらくすると、DB \ JPA関連の問題(制約、オプティミスティック・ロック、遅延ロード、重複ID、いくつかの休止状態の問題など)が驚いています。

また、実装後にテストを書くだけでなく、テストを介して開発してください。代わりにサービスの新しいメソッドの作成 - それのためのテストを作成する前に、サービスメソッドを実装し、実際のアプリケーションでそれを再チェックした後にのみ。少なくとも、サーバーをテストするよりもはるかに高速です。

だから、たくさんのテストを作成しないでください。彼らがどのようにあなたを助けてくれるかを見つけます

リポジトリ用のモックの使用はお勧めできません。あなたのサービスがHibernate \ JPA \ Databaseとどのように連携しているかをテストします。問題の大部分は、ベトナム層です。

+0

を書いてください、そして私は同意する必要があります。他のコメントで述べたように、私はすでに統合テストと設定の問題があり、コンポーネント間のやりとりはうまくいきます。私はテストをして、単体テストが必要かどうかを判断したり、postgresql +とアドオンがインストールされていることを必要とする直接の統合テストを行うことを試みています。例のテストが行​​う唯一の事は、誰かが誤って 'return null;'などのようなreturn文を偶然乱したのかどうかを判断することです。 –

+1

しかし、時には単体テストがとてもうっ血です。たとえば、バグを修正した後(リポジトリにプッシュする前に)、可能であればユニットを作成したり、統合テストを行います。そして、約30%の場合、あなたは驚かれるだろう:) –

8

質問は多少古いかもしれませんが、誰かが遭遇した場合に備えて回答をします。

  • 私はMockitoとJUnitを使用しています。
  • AccountRepositoryはJPARepositoryを拡張するプレーンなバネデータリポジトリです。
  • アカウントはプレーンなJPAエンティティです。

サービスをテストし、Springのデータリポジトリを模擬するには、以下のようなものが必要です。

package foo.bar.service.impl; 

import foo.bar.data.entity.Account; 
import foo.bar.data.repository.AccountRepository; 
import foo.bar.service.AccountService; 

import org.junit.Assert; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.mockito.InjectMocks; 
import org.mockito.Mock; 
import org.mockito.Mockito; 
import org.mockito.runners.MockitoJUnitRunner; 

@RunWith(MockitoJUnitRunner.class) 
public class AccountServiceImplTest { 

    @Mock 
    private static AccountRepository accountRepository; 

    @InjectMocks 
    private static AccountService accountService = new AccountServiceImpl(); 

    private Account account; 

    @Test 
    public void testFindAccount() { 

     Integer accountId = new Integer(1); 

     account = new Account(); 
     account.setId(accountId); 
     account.setName("Account name"); 
     account.setCode("Accont code"); 
     account.setDescription("Account description"); 

     Mockito.when(accountRepository.findOne(accountId)).thenReturn(account); 

     Account retrivedAccount = accountService.findAccount(accountId); 

     Assert.assertEquals(account, retrivedAccount); 

    } 

} 
+0

これはほとんど私がそこにいた。私はまた、このURLが役立つことがわかった:http://lkrnac.net/blog/2014/01/mock-autowired-fields/ –

1

あなたはこのライブラリを使用することができます:あなたは、任意の方法だけでなく、あなたのネイティブクエリメソッドのカスタム機能を実装できるようにしながらhttps://github.com/agileapes/spring-data-mock

これは、あなたのためにリポジトリを模擬します。