Search code examples
javamockitopowermock

Mockito/PowerMock: how to reset a mocked static variable in SUT?


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?


Solution

  • 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?