つかびーの技術日記

(情報)工学修士, 元SIer SE, 現Web系 SEの技術blogです。Scala, Java, JS, TS, Python, Ruby, AWS, GCPあたりが好きです。

MockitoはモックをInjectしてこそかなーと

   

Mockito(モヒート、モック伊藤)はJavaのモックライブラリです。モックオブジェクトを作成してユニットテストに利用することができます。

今回Mockitoを使ったり調べたりするうちに、いくつかのMockitoのサンプルコードに対して、「Injectionは?Injectionはどうするの?え?setter?」と思ったので、自分でサンプルコードを書いてみることにしました。

よくあるサンプルコード

例1

@RunWith(JUnit4.class)
public class HogeTest {

  @Test
  public void test_hoge() {
    List list = mock(List.class);
    when(list.size()).thenReturn(10);
    // 検証
    assertThat(list.size(), is(10));
  }
}

例2

@RunWith(JUnit4.class)
public class HogeTest {

  @Test
  public void test_hoge() {
    List list = mock(List.class);
    when(list.size()).thenReturn(10);
    Hoge hoge = new Hoge();
    hoge.setList(list);

    // 実行
    hoge.doSomething();

    // 検証
    assertThat(list.size(), is(10));
  }
}

良くこんな感じのサンプルを見かけます。もちろん言いたいことは分かりますし、Mockitoにちょっと触れてみるには良いと思います。

ですが、いくつか問題があるな、と思いました。

サンプルの問題

  • 例1は、単にMockitoの機能のテストをしているにすぎない
  • 例2は、MockオブジェクトをInjectする方法がsetterなので、setterがないときどうするのか不明

自分が考えるMockitoのサンプルコード

テストコード

package com.tsukaby.sample;

import java.util.List;
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.Mockito;
import org.mockito.MockitoAnnotations;

@RunWith(JUnit4.class)
public class HogeTest {

  @Mock(name = "nameList")
  private List list;

  @InjectMocks
  private Hoge hoge = new Hoge();

  @Before
  public void setup() {
    MockitoAnnotations.initMocks(this);
  }

  @Test
  public void test_hoge() {
    // 実行
    hoge.doSomething();

    // 検証
    Mockito.verify(list).addAll(Mockito.anyCollection());
  }
}

Hogeクラス

package com.tsukaby.sample;

import java.util.ArrayList;
import java.util.List;

public class Hoge {

  private List<String> nameList = new ArrayList<String>();

  public void doSomething() {
    nameList.addAll(getDatabaseValues());
    System.out.println(nameList);
  }

  private List<String> getDatabaseValues() {
    // 実際は色々処理する

    List<String> list = new ArrayList<String>();
    list.add("Taro");
    list.add("Jiro");
    list.add("Saburo");

    return list;
  }
}

Mockito、モックによるテストのポイント

  • Injectionはアノテーションで行う
    これで注入先がfieldならsetterが無くてもOKです。ローカル変数に注入したいケースもあるかもしれませんが、自分が調べた限り無理そうな感じです。
  • 検証はverifyが基本、モックオブジェクトにどういうことが起きたかを検証する
    これでモックオブジェクトに対してテスト対象のクラスがどういうことをしたかが検証できます。assertThatではできないことができます。

自分の認識ではモックでもスタブと同じことができます。thenReturnとかで。ただそれは本質ではない・・と。モックの本質はモックオブジェクトに対してどのようなことが起きたかを検証することなのではないかなーと。

以上です。

 - ツール ,