我讨厌将单元测试引入遗留代码库,但我必须这样做。
直到现在我还是使用Mockito和PowerMock成功地将单元测试引入了遗留代码库。工作得很好,直到我遇到这种情况:
// 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为空时才实例化c1和c2,因此它们(c1,c2)不会在子序列调用中重新实例化。我不明白为什么重置(c1),重置(c2)在test2中没有效果?
有什么想法吗?
答案 0 :(得分:5)
终于搞定了。基本上,我不能在两个不同的测试运行中设置存根(模拟的静态实例变量)。我必须在第一个@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中的一些限制(错误?)?
答案 1 :(得分:0)
尝试将静态模拟设置移动到@BeforeClass设置方法,但在test 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
}
...