Question

Assuming the follow tests:

public void testSingleton1() {
  Mock1 mock1 = PowerMockito.mock(Mock1.class);
  Mock2 mock2 = PowerMockito.mock(Mock2.class);

  PowerMockito.whenNew(Mock1.class).withNoArguments().thenReturn(mock1);
  PowerMockito.when(mock1.getMock2()).thenReturn(mock2);
  PowerMockito.when(mock2.method1("A", "B", "C")).thenReturn("D");

  Singleton singleton = Singleton.getInstance();
  assertEquals("D", singleton.method1("A", "B", "C"));

  Mockito.verify(mock1, Mockito.times(1)).getMock2();
  Mockito.verify(mock2, Mockito.times(1)).method1("A", "B", "C");
}

public void testSingleton2() {
  Mock1 mock1 = PowerMockito.mock(Mock1.class);
  Mock2 mock2 = PowerMockito.mock(Mock2.class);

  PowerMockito.whenNew(Mock1.class).withNoArguments().thenReturn(mock1);
  PowerMockito.when(mock1.getMock2()).thenReturn(mock2);
  PowerMockito.when(mock2.method1("B", "C", "D")).thenReturn("F");

  Singleton singleton = Singleton.getInstance();
  assertEquals("F", singleton.method1("B", "C", "D"));

  Mockito.verify(mock1, Mockito.times(1)).getMock2();
  Mockito.verify(mock2, Mockito.times(1)).method1("B", "C", "D");
}

The first test is passing successfuly but the second fails in assertion, returning null.
I think that the problem is because i'm testing a singleton and the new expectation (PowerMockito.when(mock2.method1("B", "C", "D")).thenReturn("F");) is not working.

PS: When i run only the testSingleton2() it's working correctly.

Was it helpful?

Solution

The problem is that the mock a Mock1 instance is created only in testSingleton1() and injected in the Singleton when Singleton.getInstance() is executed.

In testSingleton2() the whenNew doesn't work since the singleton constructor is not call anymore, in this case any expectations defined in testSingleton2 is taken into consideration.

To solve that i need to put all mocks and their expectations in one place:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Singleton.class, Mock1.class, Mock2.class })
public class SingletonTestCase {
  private static Mock1 mock1 = PowerMockito.mock(Mock1.class);
  private static Mock2 mock2 = PowerMockito.mock(Mock2.class);

  @BeforeClass
  public static void beforeClass() {
    PowerMockito.whenNew(Mock1.class).withNoArguments().thenReturn(mock1);
    PowerMockito.when(mock1.getMock2()).thenReturn(mock2);
    PowerMockito.when(mock2.method1("A", "B", "C")).thenReturn("D");
    PowerMockito.when(mock2.method1("B", "C", "D")).thenReturn("E");
  }

  public void testSingleton1() {
    Singleton singleton = Singleton.getInstance();
    assertEquals("D", singleton.method1("A", "B", "C"));

    Mockito.verify(mock1, Mockito.times(1)).getMock2();
    Mockito.verify(mock2, Mockito.times(1)).method1("A", "B", "C");
  }

  public void testSingleton2() {
    Singleton singleton = Singleton.getInstance();
    assertEquals("E", singleton.method1("B", "C", "D"));

    Mockito.verify(mock1, Mockito.times(2)).getMock2();
    Mockito.verify(mock2, Mockito.times(2)).method1("B", "C", "D");
  }
}

Notice that both checks consider calls to methods in previous tests

EDIT: To avoid the accumulation of calls on mocks you can use Mockito.reset(mock) on @After method to reset the mock state. It is therefore necessary to add your expectations again using an @Before, for example.

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Singleton.class, Mock1.class, Mock2.class })
public class SingletonTestCase {
  private static Mock1 mock1 = PowerMockito.mock(Mock1.class);
  private static Mock2 mock2 = PowerMockito.mock(Mock2.class);

  @Before
  public void before() {
    PowerMockito.whenNew(Mock1.class).withNoArguments().thenReturn(mock1);
    PowerMockito.when(mock1.getMock2()).thenReturn(mock2);
    PowerMockito.when(mock2.method1("A", "B", "C")).thenReturn("D");
    PowerMockito.when(mock2.method1("B", "C", "D")).thenReturn("E");
  }

  @After
  public void after() {
    Mockito.reset(mock1);
    Mockito.reset(mock2);
  }

  public void testSingleton1() {
    Singleton singleton = Singleton.getInstance();
    assertEquals("D", singleton.method1("A", "B", "C"));

    Mockito.verify(mock1, Mockito.times(1)).getMock2();
    Mockito.verify(mock2, Mockito.times(1)).method1("A", "B", "C");
  }

  public void testSingleton2() {
    Singleton singleton = Singleton.getInstance();
    assertEquals("E", singleton.method1("B", "C", "D"));

    Mockito.verify(mock1, Mockito.times(1)).getMock2();
    Mockito.verify(mock2, Mockito.times(1)).method1("B", "C", "D");
  }
}

Notice that now you can call Mockito.verify(mock1, Mockito.times(1)) and Mockito.verify(mock2, Mockito.times(1)) on testSingleton2().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top