如何验证使用Mockito调用两种方法之一?

时间:2015-09-28 17:18:55

标签: java mockito

假设我有一个有两种方法的类,我不关心哪个被称为...

public class Foo {
    public String getProperty(String key) {
        return getProperty(key, null);
    }
    public String getProperty(String key, String defaultValue) {
        //...
    }
}

以下(来自另一个类,仍在我的应用程序中)都应通过我的测试:

public void thisShouldPass(String key) {
    // ...
    String theValue = foo.getProperty(key, "blah");
    // ...
}

public void thisShouldAlsoPass(String key) {
    // ...
    String theValue = foo.getProperty(key);
    if (theValue == null) {
        theValue = "blah";
    }
    // ...
}

我不关心调用哪个,我只想要调用两个变体中的一个。

在Mockito,我通常可以这样做:

Mockito.verify(foo, atLeastOnce()).getProperty(anyString());

或者:

Mockito.verify(foo, atLeastOnce()).getProperty(anyString(), anyString());

是否有原生方式说“验证其中一个至少发生过一次”?

或者我必须做一些粗暴的事情:

try {
    Mockito.verify(foo, atLeastOnce()).getProperty(anyString());
} catch (AssertionError e) {
    Mockito.verify(foo, atLeastOnce()).getProperty(anyString(), anyString());
}

3 个答案:

答案 0 :(得分:5)

您可以将atLeast(0)ArgumentCaptor结合使用:

ArgumentCaptor<String> propertyKeyCaptor = ArgumentCaptor.forClass(String.class);
Mockito.verify(foo, atLeast(0)).getProperty(propertyKeyCaptor.capture(), anyString());

ArgumentCaptor<String> propertyKeyCaptor2 = ArgumentCaptor.forClass(String.class);
Mockito.verify(foo, atLeast(0)).getProperty(propertyKeyCaptor2.capture());

List<String> propertyKeyValues = propertyKeyCaptor.getAllValues();
List<String> propertyKeyValues2 = propertyKeyCaptor2.getAllValues();

assertTrue(!propertyKeyValues.isEmpty() || !propertyKeyValues2.isEmpty()); //JUnit assert -- modify for whatever testing framework you're using

答案 1 :(得分:3)

通常情况下,如果您在任何类型的“getter”上调用verify,那么您对实现的假设过多。 Mockito通常设计用于灵活测试(与“脆弱”测试相比,即使代码正确也需要更改);您的测试应该更关心 值是否正确,而使用哪些方法来获取该值。一个更好的解决方案可能是 stub 两个getter都返回一个可预测的值,然后对相同的值使用正常的断言以确保它连接到正确的位置。

when(mockFoo.getProperty("bar")).thenReturn("bar value");
when(mockFoo.getProperty("bar", anyString())).thenReturn("bar value");
// ...
assertEquals("bar value", new SystemUnderTest(mockFoo).getBarProperty());

Mockito的文档说明了这一点:

  

虽然可以验证存根调用,但通常它只是多余的。假设你已经存根foo.bar()。如果您的代码关心foo.bar()返回的内容,那么其他内容会中断(通常在执行verify()之前)。如果您的代码不关心get(0)返回的内容,那么它不应该被存根。

也就是说,如果这是一个你需要支持的模式(或带有重载和副作用的方法调用),你可以通过Mockito.mockingDetailsMockingDetails.getInvocations获得大量信息,包括Mockito 1.10.0的调用。您需要遍历Invocation对象以检查多个方法。

boolean found = false;
Method method1 = Foo.class.getMethod("getProperty", String.class);
Method method2 = Foo.class.getMethod("getProperty", String.class, String.class);
for (Invocation invocation : Mockito.mockingDetails(foo).getInvocations()) {
  if (method1.equals(invocation.getMethod())
      || method2.equals(invocation.getMethod()) {
    found = true;
    break;
  }
}
assertTrue("getProperty was not invoked", found);

请注意,此第二个解决方案有点危险,因为它不会受益于IDE中内置的自动重构工具,并且可能比其他一些解决方案更难阅读。 (上面也可能缺少对isIgnoredForVerificationmarkVerified以及其他细节的调用。)但是,如果您预见到需要在大型代码库中频繁使用,那么使用Mockito的内置API可能会为您提供更多帮助比你原本拥有更多的灵活性。

答案 2 :(得分:0)

在您的特定情况下,getProperty(String)会在内部调用getProperty(String, String)

public String getProperty(String key) {
    /*
     * getProperty(String, String) is called anyway.
     * Why not simply verify the occurrence of that?
     */
    return getProperty(key, null);
}

简单地验证第二种方法相当于至少验证一次或另一种的出现。

Mockito.verify(foo, atLeastOnce()).getProperty(anyString(), anyString());