[英]How can I verify that one of two methods was called using Mockito?
Suppose I have a class with two methods where I don't care which is called...假设我有一个有两种方法的类,我不在乎哪个被调用......
public class Foo {
public String getProperty(String key) {
return getProperty(key, null);
}
public String getProperty(String key, String defaultValue) {
//...
}
}
Both the below (from another class, still in my application) should pass my test:以下两个(来自另一个类,仍在我的应用程序中)都应该通过我的测试:
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";
}
// ...
}
I don't care which was called, I just want one of the two variants to be called.我不在乎调用了哪个,我只想调用两个变体之一。
In Mockito, I can generally do things like this:在 Mockito 中,我通常可以做这样的事情:
Mockito.verify(foo, atLeastOnce()).getProperty(anyString());
Or:或者:
Mockito.verify(foo, atLeastOnce()).getProperty(anyString(), anyString());
Is there a native way to say "verify either one or the other occurred at least once"?是否有一种本地方式可以说“验证一个或另一个至少发生一次”?
Or do I have to do something as crude as:或者我是否必须做一些粗略的事情:
try {
Mockito.verify(foo, atLeastOnce()).getProperty(anyString());
} catch (AssertionError e) {
Mockito.verify(foo, atLeastOnce()).getProperty(anyString(), anyString());
}
You could use atLeast(0)
in combination with ArgumentCaptor
:您可以将
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
Generally, if you're calling verify
on a "getter" of any sort, you're assuming too much about the implementation.通常,如果您在任何类型的“getter”上调用
verify
,那么您对实现的假设就太多了。 Mockito is generally designed for flexible tests (compared to "brittle" test that need to change even if the code is correct); Mockito 通常是为灵活的测试而设计的(相对于即使代码正确也需要更改的“脆弱”测试); your test should care more about whether the value is correct as opposed to which methods were used to get that value.
您的测试应该更关心的值是否正确,而不是其使用方法,获得价值。 A better solution might be to stub both getters to return a predictable value, and then use a normal assertion against the same value to ensure it plumbs through to the correct place.
更好的解决方案可能是将两个 getter存根以返回一个可预测的值,然后对相同的值使用正常的断言以确保它直通到正确的位置。
when(mockFoo.getProperty("bar")).thenReturn("bar value");
when(mockFoo.getProperty("bar", anyString())).thenReturn("bar value");
// ...
assertEquals("bar value", new SystemUnderTest(mockFoo).getBarProperty());
Mockito's documentation spells this out: Mockito 的文档说明了这一点:
Although it is possible to verify a stubbed invocation, usually it's just redundant.
尽管可以验证存根调用,但通常它只是多余的。 Let's say you've stubbed
foo.bar()
.假设您已存根
foo.bar()
。 If your code cares whatfoo.bar()
returns then something else breaks (often before evenverify()
gets executed).如果您的代码关心
foo.bar()
返回什么,那么其他东西就会中断(通常甚至在verify()
执行之前)。 If your code doesn't care whatget(0)
returns then it should not be stubbed.如果你的代码不关心
get(0)
返回什么,那么它不应该被存根。
That said, if this is a pattern you're required to support (or a method call with both overloads and side-effects) you can get a lot of information via Mockito.mockingDetails
and MockingDetails.getInvocations
, including invocations as of Mockito 1.10.0.也就是说,如果这是您需要支持的模式(或具有重载和副作用的方法调用),您可以通过
Mockito.mockingDetails
和MockingDetails.getInvocations
获得大量信息,包括自 Mockito 1.10 起的调用。 0. You would need to loop through the Invocation objects to check against multiple methods.您需要遍历 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);
Note that this second solution is a little dangerous, as it does not benefit from automatic refactoring tools built into IDEs, and may be harder to read than some other solutions.请注意,第二个解决方案有点危险,因为它无法从 IDE 中内置的自动重构工具中受益,并且可能比其他一些解决方案更难阅读。 (The above may also be missing calls to
isIgnoredForVerification
, markVerified
, and other niceties.) However, if you foresee needing this frequently across a large codebase, then using Mockito's built-in APIs may afford you much more flexibility than you would have otherwise. (以上可能还缺少对
isIgnoredForVerification
、 markVerified
和其他细节的调用。)但是,如果您预见在大型代码库中经常需要这样做,那么使用 Mockito 的内置 API 可能会为您提供比其他方式更大的灵活性。
In your particular case, getProperty(String)
calls getProperty(String, String)
internally.在您的特定情况下,
getProperty(String)
getProperty(String, 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);
}
Simply verifying the second method would be equivalent to verifying the occurrence of either one or the other at least once.简单地验证第二种方法相当于至少验证一个或另一个的出现一次。
Mockito.verify(foo, atLeastOnce()).getProperty(anyString(), anyString());
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.