java Mockito/PowerMock:如何在 SUT 中重置模拟静态变量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5786749/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mockito/PowerMock: how to reset a mocked static variable in SUT?
提问by Tumer
I hate to introduce Unit-tests into a legacy code base, but I have to.
Up untill now I successfully introduced unit-testing into the legacy code base using Mockito and PowerMock. Worked perfectly well until I met with this situation:
我讨厌将单元测试引入遗留代码库,但我必须这样做。
到目前为止,我使用 Mockito 和 PowerMock 成功地将单元测试引入了遗留代码库。工作得很好,直到我遇到这种情况:
in the SUT, there're several static varibles (which I mocked with the help of PowerMock, mocking static methods and mocking constructors).
Now in the first test method, all worked fine and the mocked static var returned the expected output value.
but in the subsequent test methods, the mocked static object always returns value that has been set in the first test, although I did call reset() on it before the tests.
在 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
}
}
Since the constructor of SUT only instantiates c1 and c2 if the static c1 is null, they (c1, c2) don't get re-instantiated in sub-sequence calls. What I don't understand is why reset(c1), reset(c2) have no effect in test2?
Any idea?
由于 SUT 的构造函数仅在静态 c1 为 null 时实例化 c1 和 c2,因此它们 (c1, c2) 不会在子序列调用中重新实例化。我不明白的是为什么 reset(c1), reset(c2) 在 test2 中没有影响?
任何的想法?
采纳答案by Tumer
Got it work finally. Basically, I can't set the stub (the mocked static instance variable) in two different test runs. I have to setup the expected behavior in the first @Before.
So instead of using
终于搞定了 基本上,我无法在两个不同的测试运行中设置存根(模拟静态实例变量)。我必须在第一个@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);
}
I should use this sequence:
我应该使用这个序列:
@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
}
Some limitation(bug?) in PowerMock/Mockito?
PowerMock/Mockito 中的一些限制(错误?)?
回答by VinnyQ77
Try moving your static mock setup to an @BeforeClass setup method, but leave your reset(mocks) call in your test setup() method. You want to setup your mockStatic only once, but because they're static, you will want to reset them for every test or they'll muddle with subsequent tests.
尝试将您的静态模拟设置移动到 @BeforeClass 设置方法,但将您的 reset(mocks) 调用保留在您的测试 setup() 方法中。您只想设置您的 mockStatic 一次,但因为它们是静态的,您将需要为每个测试重置它们,否则它们会与后续测试混淆。
i.e. try
即尝试
@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
}
...
...