JUnit5とMockitoで単体テスト

# JUnit5+Mockitoで単体テスト

## 背景
最近Java11で開発できるプロジェクトにアサインされた。まともに単体テストコードを作成する（！？）かなり丁寧なプロジェクトなのだが、
ここ1〜2年くらいJavaのプロジェクトに関わっていなかったため、「昔はこれで動いたのに今だと動かないんだ」ってことがいくつか重なったので、備忘録として記事にすることにした。

## バージョンなど
- Java 11 (OpenJDK)
- Gradle 6.5
  - Gradle 5以降でかなり変わったよね
- JUnit5 (junit-jupiter)
  - JUnit4のときからかなり変わったよね
- Mockito
  - JUnitのバージョンによってやり方違うよね

## Gradleでプロジェクト雛形作成
`gradle init`でプロジェクトディレクトリを作成。
Groovyだけじゃなくてkotlinでも`build.gralde`かけるようになったみたい。知らなかった。

```
$ mkdir pjname
$ cd pjname
$ gralde init --type java-application
Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 2

Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit 4) [1..4] 4
```

### Mockitoを依存関係に追加
https://site.mockito.org/ に追加方法が書いてあるけど、`testCompile`はGradle6.5では使えないし、kotlinの場合は書き方も違うので注意。

```build.gradle.kts
dependencies {
    // 中略

    // Mockito https://site.mockito.org/
    testImplementation("org.mockito:mockito-core:2.+")
    testImplementation("org.mockito:mockito-junit-jupiter:2.+")
}
```

## サンプルコード作成
テスト対象となる、サンプルクラスを作成。
`MainService`クラスから`SubService`クラスを呼び出す想定としている。

```java
public class MainService {
    private SubService subService = new SubService();

    public int getSum() {
        int sum = 0;
        for (int i : subService.getRandomIntegerList()) {
            sum += i;
        }
        return sum;
    }
}
```

```java
public class SubService {
    public int[] getRandomIntegerList() {
        return new int[]{8, 7, 2, 3, 6, 4, 5, 8, 4, 0};
    }
}
```

## テストコード作成
`MainService`の`getSum()`をテストするコードを作成する。

```java
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)  // JUnit5でMockito使うには必要
class MainServiceTest {

    @Mock // モック（スタブ）に置き換えたいインスタンスに定義。すべてのメソッドがモックになる
    //@Spy // 一部のメソッドだけモックにしたいときはこれを定義
    private SubService subService;

    @InjectMocks // @Mockでモックにしたインスタンスの注入先となるインスタンスに定義
    private MainService mainService;

    @Test
    public void testGetSum() {
        Mockito.when(this.subService.getRandomIntegerList()) // このモックを呼び出したとき
                .thenReturn(new int[]{10, 20, 30, 40});  //このデータを返すようにモックする
        Assertions.assertEquals(this.mainService.getSum(), 100);
    }
}
```

### `@ExtendWith`ってなに？
JUnit4では`@RunWith`だったもの。JUnit5ではこれになった。
また、Mockitoを使うときは、Mockitoが専用のExtension(`MockitoExtension`)を用意しているのでこれを指定しないといけない。

っと言うことが公式ドキュメントに書いてあるかと思ったのだが、
> https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
> 45. New JUnit Jupiter (JUnit5+) extension

↑このリンク先がない・・・たぶん以下だとおもうけど
https://javadoc.io/doc/org.mockito/mockito-junit-jupiter/latest/index.html

ちなみに、`MockitoExtension`を使うには、graldeの依存ライブラリに`mockito-junit-jupiter`を`testImplementation`で追加しないといけない。
**`testCompileOnly`で追加しても動かないので注意。**


# 所感
Mockitoは便利なのだが、使い方がわからず、あるいはモックしたいものがうまくモックされず、グーグル先生に頼ることが多い。

すぐに目的の情報が見つかればよいのだが、「SpringBootでMockitoするなら〜」とか、「JUnit4じゃないと動かないサンプルコード」とか、今それは必要な情報じゃないんだっていうサイトが上位に来て、なかなか目的の情報にたどりつけない事が多い。

たとえば、「ここをモックに置き換えたいのにうまく動かない、privatedだからかな？」と思って`private`なフィールドをモックにしたいときどうするか、って思って調べたら`PowerMock`などがあるって記事がヒットするけど、今回みたいに別に`PowerMock`使わなくてもできるし。結果的にGradleの使い方間違ってたりするだけっていう落ちだったりするし。

「テストコードになんでこんな時間費やさなきゃいけないんだ」ってストレスが貯まり始めると、テストコード書くのがおざなりになりがち。