JUnit4 でのモック

以前からJUnit には、あまり執着することがなかった。
カバレッジ率の為に無駄に近い労力をかけたくもなく、動いて当たり前のテストケースを
書くセンスの無さが厭だったからである。
今日は、今更の JUnit のことを書いてみたくなった。

static メソッドのモックを書こう。というケース

powermock は JUnit5 に対応していない。らしい。
https://github.com/powermock/powermock

powermock を使わずにモックということで、org.mockito を使うのだが、その前にまず。。。
mockito-all と、mockito-core

mockito-all は、all と名のつくとおり、 hamcrest や、objenesis の依存を含めているので
これが良いように思っていた。。

mickito-all どうやら、1.10.18 を最後に 2.x の開発がとまっている様子で
static メソッドのモックを作る MockedStatic 生成ができない。
mockito-core を使わざるをえない。

モックインスタンス注入も、
  MockitoAnnotations.initMocks(this);
と書いていたものから、
  MockitoAnnotations.openMocks(this);
という記述に変える。initMocks は、非奨励になったのだ。

Maven の pom.xml

<dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.13.1</version>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>org.mockito</groupId>
   <artifactId>mockito-core</artifactId>
   <version>4.2.0</version>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>org.mockito</groupId>
   <artifactId>mockito-inline</artifactId>
   <version>3.4.0</version>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>net.bytebuddy</groupId>
   <artifactId>byte-buddy-agent</artifactId>
   <version>1.12.6</version>
   <scope>test</scope>
</dependency>

あえて、簡単なサンプル

import javax.inject.Inject;

public class Target{
    @Inject
    private Foo foo;

    public String  view() {
        // void execute() とい戻り値のないメソッド
        foo.execute();
        // Some.value1() という String を返す static メソッド
        return "This is "+Some.value1() + ":"+ foo.getName().toUpperCase();
    }
}

この Target の view() をテストする。
Foo クラスをモックして、Some クラスの staticメソッドをモックする。

import static org.hamcrest.CoreMatchers.*;
import org.hamcrest.MatcherAssert;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
/**
 * Target Test
 */
@RunWith(JUnit4.class)
public class TargetTest{
    @Mock
    private Foo foo;

    @Before
    public void before() {
        MockitoAnnotations.openMocks(this);
    }

    @InjectMocks
    private Target target;

    @Test
    public void test() {
        try(MockedStatic<Some> mocked = Mockito.mockStatic(Some.class)){
            mocked.when(()->Some.value1()).thenReturn("A");
            Mockito.when(foo.getName()).thenReturn("abc");

            String answer = target.view();

            // 検証 assertEquals
            Assert.assertEquals("This is A:ABC", answer);
            // 検証 assertThat
            MatcherAssert.assertThat(answer, is("This is A:ABC"));
            // void メソッド execute() の実行回数
            Mockito.verify(foo, Mockito.times(1)).execute();
        }catch(Exception e){
            e.printStackTrace();
            Assert.fail();
        }
    }
}