@tsuchinoko77

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

JUnitで、メソッド内でnewしているクラスの検証をしつつ、実際の処理も実行させたい

解決したいこと

Spring Boot + Junit + Mockitoの単体テストで、
テスト対象クラス内でnewしているインスタンスをmock化しつつ、実際の処理も実行させたい

発生している問題・エラー

対象クラス内でロガーを生成しており、単体テストとしてロガーに想定通りのメッセージを出力しているかを検証しつつ、実際に出力されたログも確認したいのでログ出力処理も実行させたい。
しかし、メソッド呼び出しの検証まではできたものの、logファイルへの出力ができない。

該当するソースコード

ログ出力部品

public class LogUtility{
import org.slf4j.Logger;

    private Logger logger;

    public LogUtility(String clazz){
        logger = LoggerFactory.getLogger(clazz);
    }

    public void errorLog(String msg){
        logger.error(msg);
    }
}

テスト対象クラス

@component
@scope("step")
public class Target{
    public void execute(){
        LogUtility logUtility = new LogUtility(this.getClass().getname());
        String errorCode = "";

        //何らかの処理
        
        logUtility.errorLog("エラーコード:" + errorCode); 
    }
}

テストクラス

@RunWith(SpringUnit4ClassRunner.class)
@contextConfigration(locations = {"classpath:foo/bar.xml"})
public class TargetTest{

    @Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;

    @Before
    public void init() throws Exception {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void test() throws Exception{
        //(1)
        try(MockitoConstrction<LogUtility> mockd = mockConstruction(LogUtility.class);
        ){
            JobExecution job = jobLauncherTestUtils.launchStep("hoge");

            ArgumentCaptor<String> msgCaptor = ArgumentCaptor.forClass(String.class);
            LogUtility logUtility = mocked.constructed.get(0);
            verify(logUtility, times(1)).errorLog(msgCaptor.capture());
            assertEquals("ErrorCode", msgCaptor.getValue());
        }
    }
  
}

上記コードで、assertEqualsによる検証はできたのですが、ログファイルへの出力が行われておらず、実際のログファイルにどのように出力されているか確認することができませんでした。

自分で試したこと

①(1)の部分を以下のように変更

    try(MockitoConstrction<LogUtility> mockd = mockConstruction(LogUtility.class, 
        withSettings().useConstructor().defaultAnswer(CALLS_REAL_METHODS));
    ){
        JobExecution job = jobLauncherTestUtils.launchStep("hoge");
         //以下略
    }

結果:
ログ出力部品のlogger.error(msg);の行でNullPointerExceptionが発生した。

②以下のように変更

    try(MockitoConstrction<LogUtility> mockd = mockConstruction(LogUtility.class, 
        (mock,ctx) -> spy(mock));
    ){
        JobExecution job = jobLauncherTestUtils.launchStep("hoge");
         //以下略
    }

結果:
エラーは発生せず、テストも正常終了したものの、該当ログがlogファイルに出力されなかった。

0 likes

1Answer

private Logger logger;なので

単体テストとしてロガーに想定通りのメッセージを出力しているか

軽く見たところモックではなくスタブになっている感じがするので
リフレクションを利用し、テスト対象以外は
値を埋め込んで確認してみてはいかがでしょうか。

■参考

0Like

Comments

  1. @tsuchinoko77

    Questioner

    リフレクションを使ってlogUtility.loggerに埋め込もうとしたのですが、
    テスト対象メソッド呼び出し前のタイミングではまだMockインスタンスが生成されていないようで、上手くいきませんでした。

    モック化ができていないのは確かなようなので、Mockitoの仕様から引き続き調査したいと思います

Your answer might help someone💌