Webエンジニアのメモ帳

技術的な話を中心に書いています。

【Java】モックを使ってテストを実装する

テストにおいて、モックを使うことは必須のテクニックの一つです。

この記事ではJUnit、Mockito、PowerMockなどのライブラリを使いながら、モックを使ってテストを行う方法を説明します。

まずは普通にテストする

テスト対象のコードは以下とします。

public class Sample {
  public String greeting() {
    String name = getName();
    return "こんにちは、" + name + "さん!";
  }

  public String getName() {
    return "山本";
  }
}

まずはモックなどは使わず、greeting()を普通にテストしてみます。

import org.junit.Test;
import static org.junit.Assert.assertThat;
import static org.hamcrest.Matchers.is;

public class SampleTest {
  @Test
  public void greetingTest() {
    Sample sample = new Sample();
    assertThat(sample.greeting(), is("こんにちは、山本さん!"));
  }
}

テスト対象のコードの一部のpublicメソッドをモック化する場合

テストコードのgetName()が、例えばデータベースに接続してあれこれして返す、みたいな処理だとします。

public class Sample {
  public String greeting() {
    String name = getName();
    return "こんにちは、" + name + "さん!";
  }

  public String getName() {
    // DBに接続し、あれこれ処理をして、Stringを返す処理が記述されているとします。
  }
}

そうした場合、greeting()をテストしたい場合、getName()メソッドをモック化する必要があります。

その場合、テストコードは以下のようになります。

import org.junit.Test;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.doReturn;
import static org.junit.Assert.assertThat;
import static org.hamcrest.Matchers.is;

public class SampleTest {
  @Test
  public void greetingTest() {
    Sample sampleMock = spy(new Sample());
    doReturn("田中").when(sampleMock).getName();
    assertThat(sampleMock.greeting(), is("こんにちは、田中さん!"));
  }
}

spy()を使うことで、Sampleクラスのインスタンスをモック化しています。

なお

Sample sampleMock = mock(Sample.class);

ではなく

Sample sampleMock = spy(new Sample());

としているのは、mock()を使う場合には、呼び出されるすべての関数の挙動を記述する必要があるためです。

今回はSampleクラスに関してgetName()の挙動はモック化しつつ、greeting()関数はそのまま使いたかったので、spy()を使っています。

テスト対象のコードの一部のprivateメソッドをモック化する場合

テスト対象のコードが以下のようだった場合を考えます。

public class Sample {
  public String greeting() {
    String name = getName();
    return "こんにちは、" + name + "さん!";
  }

  private String getName() {
    // DBに接続し、あれこれ処理をして、Stringを返す処理が記述されているとします。
  }
}

先ほどと同じく、greeting()のテストをしたいときに、getName()をモック化する必要があります。

しかし、getName()が先ほどのようにpublicでなくprivateであれば、方法が変わってきます。

この場合、powerMockというモジュールが重宝します。

import org.junit.Test;
import static org.mockito.Mockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.junit.Assert.assertThat;
import static org.hamcrest.Matchers.is;
public class SampleTest {
  @Test
  public void greetingTest() throws Exception{
    Sample sampleMock = spy(new Sample());
    when(sampleMock, "getName").thenReturn("鈴木");
    assertThat(sampleMock.greeting(), is("こんにちは、鈴木さん!"));
  }
}

なお、上記のコードではMockitoではなくPowerMockitoのwhen()を使っている点に注意が必要です。

when(モック化したインスタンス名, メソッド名, 引数).thenReturn("返り値")

とすることで、privateメソッドもモック化することができます。

補足 pom.xmlの記述

今回ご紹介したライブラリを使うにあたっては、pom.xmlまたはbuild.gradleでの記述が必要です。

私が使用したpom.xmlの<dependencies>部分は以下の通りです。

<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
  </dependency>
  <dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-library</artifactId>
    <version>1.3</version>
  </dependency>
  <dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.8.9</version>
  </dependency>
  <dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
  </dependency>
</dependencies>

なおorg.mockito と org.powermock のバージョンはそれぞれ互換性がないものがあるので、注意してください。