2017-10-30 50 views
3

異なるサブ呼び出しまたはメソッド自体から来る例外をキャッチし、例外メッセージを記録する静的メソッドをテストしようとしています。要件によって、メソッドの実装を変更することはできません。この場合、スパイリング・サブコールはオプションではありません。テストで一貫性を持たせたい場合や、メソッド本体自体から例外をスローする場合があるため、最終的にエラー・ログ・メッセージをチェックしました。Mockito.doAnswer(...)を使用した重複した応答処理

したがって、メソッドから呼び出されるロガーを疑似し、ロガーが特定のメッセージに一致するエラー(...)を呼び出すときにロギング呼び出しに応答を追加します。これまでのところ私の面ではとても良い。私は何をすべきかの例は以下の通りです:

Mockito.doAnswer(new Answer<Void>() 
{ 
    @Override 
    public Void answer(InvocationOnMock invocation) throws Throwable { 
     Object[] args = invocation.getArguments(); 
     String errorMessage = (String) args[0]; 
     assertTrue(errorMessage.contains(SPECIFIC_MESSAGE)); 
     return null; 
    } 
}).when(logger).error(Matchers.startsWith(GENERIC_PREFIX)); 

我々はLoggerFactory.getLogger(...)

Logger logger = Mockito.mock(Logger.class); 
PowerMockito.mockStatic(LoggerFactory.class); 
Mockito.when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger); 

から私たちの嘲笑ロガー今すぐ来て、静的呼び出しを模擬するためにPowerMockitoを使用することを決めたと戻りました我々の問題:

各テストで、変更を確認するメッセージSPECIFIC_MESSAGEの値。そこで、各テストのロガーをモックし、静的なLoggerFactory呼び出しをモックしてロガーを返し、次に特定の答えをこの特定のインスタンスのlogger.error(...)呼び出しに追加します。しかし最初のテスト中にlogger.error呼び出しに追加される最初の回答は、他のすべての回答を上書きしているようです。各テストで同じ実行が行われます。

私は、問題はMockitoから来て、シングルトンモックを返すことができると思っていましたが、私はそれをテストしましたが、そうではありません。私の問題はLoggerFactory.getLogger(...)呼び出しから来て、いつも同じロガーのインスタンスを返すが、どちらのケースも返さないと思った。ここでは、関連する実行ログトレースを使用してコードを実行しているのと同じ問題を示す実装を示します。

import java.util.Arrays; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

public class App 
{ 
    public static Logger logger = LoggerFactory.getLogger(App.class); 

    public static void main(String[] args) 
    { 
     logger.error("Error = " + Arrays.toString(args)); 
    } 
} 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.mockito.Matchers; 
import org.mockito.Mockito; 
import org.mockito.invocation.InvocationOnMock; 
import org.mockito.stubbing.Answer; 
import org.powermock.api.mockito.PowerMockito; 
import org.powermock.core.classloader.annotations.PrepareForTest; 
import org.powermock.modules.junit4.PowerMockRunner; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

import static org.mockito.Mockito.*; 
import static org.junit.Assert.*; 

@RunWith(PowerMockRunner.class) 
@PrepareForTest({LoggerFactory.class}) 
public class AppTest 
{ 
    @Test 
    public void firstTest() 
    { 
     Logger logger = Mockito.mock(Logger.class); 
     PowerMockito.mockStatic(LoggerFactory.class); 
     Mockito.when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger); 

     Mockito.doAnswer(new Answer<Void>() 
     { 
      @Override 
      public Void answer(InvocationOnMock invocation) throws Throwable { 
       Object[] args = invocation.getArguments(); 
       String errorMessage = (String) args[0]; 
       System.out.println("Calling from firstTest"); 
       assertTrue(errorMessage.contains("a")); 
       return null; 
      } 
     }).when(logger).error(Matchers.startsWith("Error")); 

     App.main(new String[]{ "a" }); 
    } 

    @Test 
    public void secondTest() 
    { 
     Logger logger = Mockito.mock(Logger.class); 
     PowerMockito.mockStatic(LoggerFactory.class); 
     Mockito.when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger); 

     Mockito.doAnswer(new Answer<Void>() 
     { 
      @Override 
      public Void answer(InvocationOnMock invocation) throws Throwable { 
       Object[] args = invocation.getArguments(); 
       String errorMessage = (String) args[0]; 
       System.out.println("Calling from secondTest"); 
       assertTrue(errorMessage.contains("b")); 
       return null; 
      } 
     }).when(logger).error(Matchers.startsWith("Error")); 

     App.main(new String[]{ "b" }); 
    } 
} 

TRACE:

Calling from firstTest 
Calling from firstTest 

二答えが処理されない理由を任意のアイデア?前もって感謝します。

EDIT:

問題は、実際には静的メソッドモックから来ています。 "それでは、私の問題はLoggerFactory.getLogger(...)呼び出しから来て、いつも同じロガーのインスタンスを返すが、どちらのケースも返さないと思った。実際には間違っています。私のテストではgetLogger(...)を呼び出すことでテスト内で偽装されたロガーモックが返されますが、実際にApp.main(...)メソッドを呼び出すときには、main()メソッドのmocked getLogger (...)は常に同じインスタンスを返し、期待どおりにテスト間でリセットされません。 Mockitoは、ドキュメントごとのテストの間でリセットすることになっています。 mockitoのバグや制限? MockitoとPowerMockitoのやりとりに関係する問題?

+0

https://github.com/answer-it/mock-slf4j/またはhttp://projects.lidalia.orgをご覧ください。uk/slf4j-test/ –

+0

参考にしていただき、ありがとうございます。これは、ログに記録されたメッセージを「スパイ」するためのソリューションになる可能性があります。私のケースでは何が問題になるのだろうと思っています。つまり、異なる回答が特定のロガーインスタンスに個別に割り当てられている場合、なぜ1つの回答がすべてのロガーに関連付けられているのでしょうか。 – Maaaatt

答えて

0

私は、テストごとにメソッドレベルで静的模擬にクラスを準備する解決策を見出しました。 署名の前に@PrepareForTest(LoggerFactory.class)を追加すると、実際には、ロガーファクトリモックがテスト間でリセットされていないという問題が解決されました。したがって、最初のコールMockito.when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger);は常に有効で常に同じロガーを返します。

+0

'any(Class.class) 'を使うのではなく明示的にクラスを指定するのも助かります。 – Arkadiy

+0

他のユースケースでは間違いありませんが、このクラスではほとんどの例外が収束し、ログメッセージをテストしています。このクラスに1つのロガーしかないので、クラスを指定しても実際に何が起こっているのかは変わりません。私はクラスを指定することができたが、それはほとんどバニラと思う。私が見ることができないものがなければ。 – Maaaatt

関連する問題