在测试Singleton时使用PowerMockito进行断言失败

时间:2014-04-08 14:41:54

标签: java mocking mockito powermock

假设以下测试:

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");
}

第一个测试是成功通过,但第二个测试失败,返回null 我认为这个问题是因为我正在测试一个单例和新的期望( PowerMockito.when(mock2.method1(“B”,“C”,“D”))。thenReturn(“F”); )无效。

PS:当我只运行testSingleton2()时,它正常工作。

1 个答案:

答案 0 :(得分:3)

问题是模拟Mock1实例只在testSingleton1()中创建,并在执行Singleton.getInstance()时在Singleton中注入。

在testSingleton2()中,whenNew不起作用,因为单例构造函数不再调用,在这种情况下,会考虑testSingleton2中定义的任何期望。

要解决这个问题,我需要将所有模拟和期望放在一个地方:

@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");
  }
}

请注意,两项检查均考虑在之前的测试中调用方法

编辑:为避免在模拟上调用累积,您可以在@After方法上使用Mockito.reset(mock)来重置模拟状态。因此,有必要使用@Before再次添加您的期望,例如。

@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");
  }
}

请注意,现在您可以在testSingleton2()上调用Mockito.verify(mock1,Mockito.times(1))和Mockito.verify(mock2,Mockito.times(1))。