6

レガシー コード ベースに単体テストを導入するのは嫌いですが、導入する必要があります。
これまで、Mockito と PowerMock を使用して、従来のコード ベースに単体テストを導入することに成功しました。この状況に遭遇するまで、完全にうまく機能しました:

SUT には、いくつかの静的変数があります (PowerMock を使用してモックし、静的メソッドをモックし、コンストラクターをモックしました)。
最初のテスト メソッドでは、すべてが正常に機能し、モックされた静的変数が期待される出力値を返しました。
しかし、後続のテスト メソッドでは、テストの前に reset() を呼び出しましたが、モック化された静的オブジェクトは常に最初のテストで設定された値を返します。

// legacy code base:
public class SUT {
  private static Collaborator1 c1 = null;
  private static Collaborator2 c2 = null;

  public SUT(param1) {
    if (c1 == null) {
        c1 = Collaborator1.instance(param1);
        c2 = new Collaborator2(c1);
    } else {
    }
  }
}



// newly introduced unit tests:
@RunWith(PowerMockRunner.class)
@PrepareForTest({
    SUT.class,                  // to mock: new Collaborator2(..), as required by PowerMock when mocking constructors
    Collaborator1.class,        // to mock: Collaborator1.instance(..), as required by PowerMock in mocking static methods
})
public class SUTTest {

  private SUT sut;

  private Collaborator1 c1 = mock(Collaborator1.class);
  private Collaborator2 c2 = mock(Collaborator2.class);

  @Before  
  public void setup() {
    // mock c1:
    PowerMockito.mockStatic(Collaborator1.class);
    when(Collaborator1.instance(param1)).thenReturn(c1);

    // mock c2:
    PowerMockito.whenNew(Collaborator2.class).withArguments(c1).thenReturn(c2);

    reset(c1);
    reset(c2);

    sut = new SUT(param1);
  }

  @Test
  public void test1() {
    when(c2.foo(input1)).thenReturn(out1); 

    // do something
  }

  @Test
  public void test2() {
    when(c2.foo(input2)).thenReturn(out2);    // BANG!!! c2.foo(input2) always return "out1"

    // do something
  }
}



SUT のコンストラクターは、静的な c1 が null の場合にのみ c1 と c2 をインスタンス化するため、それら (c1、c2) はサブシーケンス呼び出しで再インスタンス化されません。私が理解していないのは、リセット(c1)、リセット(c2)がtest2で効果がない理由です?

何か案が?

4

2 に答える 2

5

ようやく機能しました。基本的に、2 つの異なるテスト実行でスタブ (モックされた静的インスタンス変数) を設定することはできません。最初の @Before で期待される動作をセットアップする必要があります。
したがって、使用する代わりに

  @Before  
  public void setup() {
    ...
  }

  @Test
  public void test1() {
    when(c2.foo(input1)).thenReturn(out1); 
  }

  @Test
  public void test2() {
    when(c2.foo(input2)).thenReturn(out2); 
  }

このシーケンスを使用する必要があります。

@Before  
  public void setup() {
    when(c2.foo(input1)).thenReturn(out1); 
    when(c2.foo(input2)).thenReturn(out2);
  }

  @Test
  public void test1() {
    // do something
  }

  @Test
  public void test2() {
    // do something
  }

PowerMock/Mockito のいくつかの制限 (バグ?)?

于 2011-04-27T04:59:21.640 に答える
1

静的モックのセットアップを @BeforeClass セットアップ メソッドに移動してみてください。ただし、テスト用の setup() メソッドには reset(mocks) 呼び出しを残しておいてください。mockStatic を一度だけセットアップしたいが、それらは静的であるため、テストごとにリセットするか、後続のテストで混乱します。

つまり、試してみる

@BeforeClass  
public void setupClass() {
    // mock c1:
    PowerMockito.mockStatic(Collaborator1.class);
    when(Collaborator1.instance(param1)).thenReturn(c1);

    // mock c2:
    PowerMockito.whenNew(Collaborator2.class).withArguments(c1).thenReturn(c2);
}

@Before  
public void setup() {
  reset(c1);
  reset(c2);

  sut = new SUT(param1);
}

@Test
public void test1() {
  // do something
}

...

于 2016-04-01T20:27:00.337 に答える