LoginSignup
15
22

More than 3 years have passed since last update.

JUnit5とMockitoで単体テスト

Posted at

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クラスを呼び出す想定としている。

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

    public int getSum() {
        int sum = 0;
        for (int i : subService.getRandomIntegerList()) {
            sum += i;
        }
        return sum;
    }
}
public class SubService {
    public int[] getRandomIntegerList() {
        return new int[]{8, 7, 2, 3, 6, 4, 5, 8, 4, 0};
    }
}

テストコード作成

MainServicegetSum()をテストするコードを作成する。

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-jupitertestImplementationで追加しないといけない。
testCompileOnlyで追加しても動かないので注意。

所感

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

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

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

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

15
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
22