2016-06-14 20 views
0
@Test 
    public void onConnectionCompletedTest() { 
     connectionProvider.initialize(); 
     connectionProvider.addEventObserver(SocketEvent.Type.SOCKET_CONNECT, mockedObserver); 
     connectionProvider.onConnectionCompleted(mockedChannel); 

     verify(mockedObserver).socketEventObserved(socketEventCaptor.capture()); 
     Assert.assertEquals(SocketEvent.Type.SOCKET_CONNECT, socketEventCaptor.getValue().getType()); 
    } 


@Test 
    public void onConnectionClosedTest() { 
     connectionProvider.initialize(); 
     connectionProvider.addEventObserver(SocketEvent.Type.SOCKET_DISCONNECT, mockedObserver); 
     connectionProvider.onConnectionClosed(mockedChannel); 

     verify(mockedObserver).socketEventObserved(socketEventCaptor.capture()); 
     Assert.assertEquals(SocketEvent.Type.SOCKET_DISCONNECT, socketEventCaptor.getValue().getType()); 
    } 

これらのテストを両方実行すると、2番目のテストが失敗するという問題があります。しかし、私がコメントアウトすると、Java Mockitoの1つのテストで別のテストが失敗する

verify(mockedObserver).socketEventObserved(socketEventCaptor.capture()); 
     Assert.assertEquals(SocketEvent.Type.SOCKET_CONNECT, socketEventCaptor.getValue().getType()); 

となり、2回目のテストに合格します。これにはさまざまなクラス/メソッドが含まれていますので、これが説明を思い付くには十分な情報です。

私が取得エラー:正確

wanted but not invoked: 
mockedObserver.socketEventObserved(
    <Capturing argument> 
); 
-> at com.crestron.cnx.cip.io.ConnectionProviderTest.onConnectionClosedTest(ConnectionProviderTest.java:188) 
Actually, there were zero interactions with this mock. 

私の質問:どのように私は最初のテストを@ignoreとき、第二が通過することが起きているだろうか?

編集:私は重要な@Beforeクラスを持っています。

@Before 
    public void init() { 
     MockitoAnnotations.initMocks(this); 
     JsonParser parser = new JsonParser(); 
     JsonElement jsonElement = parser.parse(json); 
     configurationService.loadConfiguration(jsonElement, "id"); 
     AppContext.getContext().applyConfiguration(configurationService); 
     connectionProvider = ConnectionProvider.newInstance(); 

    } 

最初と最後の行ではないものはすべて無視できます。新しいConnectionProviderオブジェクトを作成します。したがって、2つの別々のオブジェクトで動作しているため、1つのテストは別のテストに影響しないと思うでしょう。

+0

あなたは初期化テストにモックをリセットしますか?また、テスト中のクラスの新しいインスタンスを作成することもできます。 – yonisha

+0

このウェブサイトには投稿していないため、これが正しくフォーマットされるかどうかは不明です。 @Before公共ボイドのinit(){ MockitoAnnotations.initMocks(本) JsonParserパーサー=新しいJsonParser(); JsonElement jsonElement = parser.parse(json); configurationService.loadConfiguration(jsonElement、 "id"); AppContext.getContext()。applyConfiguration(configurationService); connectionProvider = ConnectionProvider.newInstance();私は私のメインの記事を編集した }。 –

+0

あなたがMockitoAnnotation.initMocksを()を使用している、あなたのモックは「@Mock」アノテーションを付けていますか? – yonisha

答えて

2

これはあなたが考えるよりも簡単です。テストは、実行の2番目のテストであるときにsocketEventObservedが呼び出されないため、これらの行をコメントアウトすると機能します。これはおそらく上に投稿していないコードの問題です。どこにでもブレークポイントを設定socketEventObservedその

  • まず第一に、:それは犯人が、コードの非現実的なボリュームに埋設されていてもよいと思われますので

    、ここではいくつかのデバッグのヒントとテスト汚染の一般的な源は、シングルテスト実行とマルチテスト実行を比較します。あなたがMockitoと同じ振る舞いを見たら、それはMockitoではありません。

  • このケースでは、他のスレッド(特にリスナー)で発生する可能性がある操作に注目してください。 Mockito timeoutを使用すると、そこに助けることができます。

    verify(mockedObserver, timeout(2000)) 
        .socketEventObserved(socketEventCaptor.capture()); 
    
  • あなたはテストの一定数が実行されたときにのみ起動することができ、時にはバッファリングや紅潮ポリシーを伴うI/Oチャンネル、で作業しているように見える、またはテストの場合特定の順序で実行されます。 @Beforeメソッドが、コードが触れる可能性のあるモードやバッファを含め、状態を完全にリセットすることを確認してください。

  • AppContext.getInstance()ConnectionProvider.newInstance()(どちらも静的メソッド呼び出し)と対話します。名前にもかかわらずインスタンスを節約しない限り、後者についてはあまり心配していませんが、前者は複数の初期化に親切に対応していない可能性があります。一般に、テスト中のシステムでは、グローバル状態への書き込みに注意を払ってください。

  • モッキート自体が静的状態を維持します。 Mockitoは内部状態を静的でスレッドスコープ(ThreadLocal経由)に保ちますが、テストではMockitoを検出できない無効な内部状態にすることがあります(たとえば、操作が半分完了したなど)。このケースを検出する@Afterメソッドを追加してください:

    @After public void checkMockito() { Mockito.validateMockitoUsage(); } 
    

    ...または、自動的にMockitoRuleまたはMockitoJUnitRunner、これを行うとinitMocks(this)の使用に切り替えます。

  • 最後に、Mockitoは完璧ではない:それはそれらがへのコンパイラを必要としても(それは黙ってfinal方法およびネストされたクラスでは動作し、いくつかの非public方法を模擬するために失敗することを意味する、メソッドをオーバーライドするために、プロキシオブジェクトを使用していますあなたが見ることができない合成方法を生成する)。あなたのmockedObserverは、最終的なまたは限定された視認性のメソッドを持っている場合、それは実際のコードと嘲笑のコードは、ハード・ツー・予測システムの動作を作る方法で相互作用する可能性があります。

+0

ご意見ありがとうございます。一度に複数のスレッドが実行されていたので、それはうんざりしていたことが判明しました。現在、Junitに組み込まれた方法があるかどうかを探しています。 –

+0

@Josh 'verify'は、呼び出しカウントなどの設定を含む2番目のパラメータを取ることができます。 'timeout'はあなたの場合に特に便利です。メソッド呼び出しが発生するまでに指定された時間(ミリ秒)待機します。 –

+0

ありがとうございました!おそらくタイムアウトにするよりも良い方法があるかもしれないと思うが、それは私が正直にやっている解決策だからだ。 –

関連する問題