mockitoとGuiceの組み合わせ

2018年1月26日

これまでの例では、モックオブジェクトを作成してそれを明示的に操作することにした。このモックオブジェクトをテスト対象オブジェクトに「注入」するにはどうしたらよいか?

以下は、UserManagerのloginフィールドにLoginインスタンスを注入し、startManageから間接的にlogin()メソッドを呼び出す例である。

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import org.junit.*;

import com.google.inject.*;

public class TestZero {

  // ユーザマネージャ
  static class UserManager {
    @Inject Login login;
    boolean startManage() {
      return login.login("foo", "bar");
    }
  }

  // ログインインターフェース
  public interface Login {
    boolean login(String user, String password);
  }    

  @Test
  public void test() {
    final Login mock = mock(Login.class);

    // ("foo", "bar")で呼び出されたときはtrueを返す。
    when(mock.login("foo", "bar")).thenReturn(true);

    // Guiceインジェクタを作成    
    Injector injector = Guice.createInjector(new Module[] {
        new AbstractModule() {
          @Override protected void configure() {
      // Login.classをmockインスタンスにバインド
            bind(Login.class).toInstance(mock);
          }
        }
    });

    // ユーザマネージャを作成してstartManageを呼び出し    
    UserManager manager = injector.getInstance(UserManager.class);
    assertTrue(manager.startManage());

    // ("foo", "bar")のパラメータで一度だけ呼び出されたことを確認
    verify(mock).login("foo", "bar");    
  }
}

上のようにしてしまうと、@Inject Loginには常にただ一つのインスタンス(mock)が注入されてしまう。つまりシングルトン扱いになってしまうので注意が必要である。