假设我有一个有两种方法的类,我不关心哪个被称为...
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());
}
答案 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.mockingDetails
和MockingDetails.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中内置的自动重构工具,并且可能比其他一些解决方案更难阅读。 (上面也可能缺少对isIgnoredForVerification
,markVerified
以及其他细节的调用。)但是,如果您预见到需要在大型代码库中频繁使用,那么使用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());