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:
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.
// 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?
Advertisement
Answer
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 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?