web-dev-qa-db-ja.com

Mockito @InjectMocksはどのように機能しますか?

ここに私の質問があります:

すべてのメソッドが汎用サービスから継承されることをテストするために、いくつかのWebサービスクラスがあります。それぞれの単体テストを作成するのではなく、機能別のテストスイート(つまり、それぞれ異なる基になるDAOメソッド呼び出しに依存するテストメソッドの3つのグループ)を分類できると考えています。

私が提案するのは:

@Mock StateDAO mockedStateDao;
@Mock CountyDAO mockedCountyDao;
@Mock VisitorDAO mockedVisitorDao;

次に呼び出します:

@InjectMocks CountyServiceImpl<County> countyService = new CountyServiceImpl<County>();
@InjectMocks StateServiceImpl<State> stateService = new StateServiceImpl<State>();
@InjectMocks VisitorServiceImpl<Visitor> visitorService = new VisitorServiceImpl<Visitor>();

各mockedDAOが正しいサービスに挿入されることをどのようにして確認できますか? @InjectMocksを使用するよりも、3つすべてを自動配線する方が簡単でしょうか?

Spring、Hibernate、Mockitoを使用しています...

18
DYezek

ニコラスの答えはほとんど正しいですが、 InjectMocks のjavadocを見て推測する代わりに、詳細が含まれています;)

私にとって、1つのテストで非常に多くのサービスを使用するのは奇妙です。単体テストとして、または統合テストとしては適切ではないと感じます。単体テストでは、協力者が多すぎて、オブジェクト指向(またはSOLID)に見えないため、間違っています。統合テストでは、DBとの統合をテストするコードがモックではないため、奇妙です。

1.9.5の迅速な参照については、次のものがあります。

注入を実行するフィールドをマークします。

ショートハンドのモックとスパイ注入を許可します。モックとスパイの繰り返し注入を最小限に抑えます。 Mockitoは、コンストラクターインジェクション、セッターインジェクション、またはプロパティインジェクションのいずれかによってのみ、また以下で説明するように、モックをインジェクトしようとします。次の戦略のいずれかが失敗した場合、Mockitoは失敗を報告しません。つまり、依存関係を自分で提供する必要があります。

  1. コンストラクター注入;最大のコンストラクターが選択され、テストでのみ宣言されたモックで引数が解決されます。

    注:引数が見つからない場合、nullが渡されます。非モック可能な型が必要な場合、コンストラクター注入は発生しません。これらの場合、依存関係を自分で満たす必要があります。

  2. プロパティセッターインジェクション;モックは最初にタイプによって解決され、次に同じタイプのプロパティが複数ある場合は、プロパティ名とモック名。

    注1:同じタイプ(または同じ消去)のプロパティがある場合、すべての@Mockアノテーション付きフィールドに一致するプロパティを指定することをお勧めします。そうしないと、Mockitoが混乱してインジェクションされる可能性があります起こらない.

    注2:@InjectMocksインスタンスが以前に初期化されておらず、引数なしのコンストラクターがある場合、このコンストラクターで初期化されます。

  3. フィールドインジェクション;モックは最初にタイプによって解決され、次に同じタイプのプロパティが複数ある場合は、フィールド名とモック名。

    注1:同じタイプ(または同じ消去)のフィールドがある場合、すべての@Mock注釈付きフィールドに一致するフィールドの名前を付ける方が良いです。そうしないと、Mockitoが混乱してインジェクションされる可能性があります起こらない.

    注2:@InjectMocksインスタンスが以前に初期化されておらず、引数なしのコンストラクターがある場合、このコンストラクターで初期化されます。

22
Brice

複数のサービスがあり、Springベースの環境でDAOをモックオブジェクトに置き換える場合は、Springockitoを使用することをお勧めします。 https://bitbucket.org/kubek2k/springockito/wiki/Home

ここにも記載されています: MockitoモックをSpring Beanに注入する

Testclassは次のようになります。

@RunWith (SpringJUnit4ClassRunner.class)
@ContextConfiguration (loader = SpringockitoContextLoader.class, locations =    {"classpath:/org/example/package/applicationContext.xml"})
public class NameOfClassTest {

    @Autowired
    @ReplaceWithMock 
    StateDAO mockedStateDao;

    @Autowired
    @ReplaceWithMock 
    CountyDAO mockedCountyDao;

    @Autowired
    @ReplaceWithMock 
    VisitorDAO mockedVisitorDao;

@Testまたは@Before Methodeでは、標準のMockitoの方法でモックをセットアップできます。

Mockito.doReturn(null).when(mockedCountyDao).selectFromDB();
3
giesemic

さて、静的メソッド MockitoAnnotations.initMocks(Object) はbootstrapプロセス全体に使用されます。

ソースコードを参照していないため、どのように機能するかはわかりませんが、次のように実装します。

  1. @Mockアノテーションを使用して、渡されたObjectのクラスでメンバー変数をスキャンします。
  2. それぞれについて、そのクラスのモックを作成し、そのメンバーに設定します。
  3. @InjectMocksアノテーションを使用して、渡されたObjectのクラスでメンバー変数をスキャンします。
  4. 見つかった各メンバーのクラスをスキャンして、(2)で作成されたモックオブジェクトのいずれか(つまり、フィールドが親クラス/インターフェース、または宣言されたモックオブジェクトと同じクラス)のいずれかを挿入できるメンバーを探しますクラス)、そのメンバーに設定します。
1

気にせず、オンラインで見てください。InjectMocksアノテーションは@Mockアノテーションを持つものをフィールドとして扱い、静的スコープ(クラス全体)であるため、モックが正しいサービスに行くことを保証できませんでした。これは、クラスレベルではなく、機能レベルでユニットテストを試みるためのやや思考実験でした。このものをSpringで自動配線するだけだと思います...

0
DYezek