문제

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.

도움이 되었습니까?

해결책

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().

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top