web-dev-qa-db-ja.com

Mockitoを使用してメソッドのローカル変数をモックする

テストする必要があるクラスAがあります。以下は、Aの定義です。

public class A {
    public void methodOne(int argument) {
        //some operations
        methodTwo(int argument);
        //some operations
    }

    private void methodTwo(int argument) {
        DateTime dateTime = new DateTime();
        //use dateTime to perform some operations
    }
}

また、dateTime値に基づいて、データベースから取得した一部のデータを操作します。このデータベースの場合、値はJSONファイルを介して永続化されます。

これは事態を複雑にします。必要なのは、テスト中にdateTimeを特定の日付に設定することです。 mockitoを使用してローカル変数の値をモックする方法はありますか?

28
user657592

ローカル変数をモックすることはできません。ただし、できることは、その作成をprotectedメソッドとspy itに抽出することです。

public class A {
  public void methodOne(int argument) {
    //some operations
    methodTwo(int argument);
    //some operations
  }

  private void methodTwo(int argument) {
    DateTime dateTime = createDateTime();
    //use dateTime to perform some operations
  }

  protected DateTime createDateTime() {
    return new DateTime();
  }
}

public class ATest {
  @Test
  public void testMethodOne() {
    DateTime dt = new DateTime (/* some known parameters... */);
    A a = Mockito.spy(new A());
    doReturn(dt).when(a).createDateTime();
    int arg = 0; // Or some meaningful value...
    a.methodOne(arg);
    // assert the result
}
31
Mureinik

このような問題に対処する最良の方法は、DateTimeの新しいインスタンスを取得するために使用される、挿入されたClockサービスを使用することです。そのようにして、テストは、現在の時刻ではなく特定のDateTimeを返すモックClockを挿入できます。

新しいJava 8時間APIは、特にその目的のために、このような Clockクラス を定義しています。

2
JB Nizet

返事が遅れて申し訳ありません。

これは手間がかかりすぎるかもしれませんが、ローカル変数を提供できるオブジェクトをモックすると、そのモックを返すことができます。テストを簡単にするためにコードを再構築するのではなく、検討する必要があります。

_public class A {

    DateTimeFactory factory;

    private void method() {
        DateTime dateTime = factory.getDateTime();
        //use dateTime to perform some operations
    }
}
_

テストでは、次のようなことができます:when(factoryMock.getDateTime()).doReturn(dateTimeMock)

工場のモックを何らかの形でクラスに注入する必要があります。

0
Matt