Java 模棱两可的Mockito-应为0个匹配器,记录了1个(InvalidUseOfMatchersException)

Java 模棱两可的Mockito-应为0个匹配器,记录了1个(InvalidUseOfMatchersException),java,junit,mocking,mockito,Java,Junit,Mocking,Mockito,我面临一个非常奇怪的问题 URL = "/my/specific/url/"; when(this.restHelperMock.post( eq(myEnum), eq(this.config.apiEndpoint() + URL), any(JSONObject.class))).thenReturn(new JSONObject(myDesiredJsonContent)); 或者甚至是包含 URL = "/my/specific/url/"; when(this.res

我面临一个非常奇怪的问题

 URL = "/my/specific/url/";
 when(this.restHelperMock.post(
 eq(myEnum),
 eq(this.config.apiEndpoint() + URL),
 any(JSONObject.class))).thenReturn(new JSONObject(myDesiredJsonContent));
或者甚至是包含

 URL = "/my/specific/url/";
 when(this.restHelperMock.post(
 eq(myEnum),
 contains(this.config.apiEndpoint() + URL),
 any(JSONObject.class))).thenReturn(new JSONObject(myDesiredJsonContent));
给我

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
0 matchers expected, 1 recorded:

This exception may occur if matchers are combined with raw values:
    //incorrect:
    someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
    //correct:
    someMethod(anyObject(), eq("String by matcher"));

For more info see javadoc for Matchers class.
即使我不使用原始表达式。
奇怪的是,如果我将contains方法更改为:

URL = "/my/specific/url/";
 when(this.restHelperMock.post(
 eq(myEnum),
 contains(URL),
 any(JSONObject.class))).thenReturn(new JSONObject(myDesiredJsonContent));
省略端点,它就工作了

Config和RestHelper都是模拟的:

this.restHelperMock = mock(RESTHelper.class);
this.config = mock(MyBMWConfiguration.class);

when(this.config.apiEndpoint()).thenReturn("http://host:port/api");
ApiEndpoint的URL与我想要模拟的URL相同, 即使不是这样,我也应该得到一个NullpointerException,因为它是错误的模拟。 但在这里我没有任何想法


谢谢您的回答。

问题似乎是您在
eq(…)
调用期间调用了一个模拟方法
this.config.apidendpoint()
。尝试简单地将完整的URL放在那里(主机:port/api/my/specific/URL),而不是在那里调用另一个mock,这可能会混淆Mockito,因为它依赖于内部状态进行模拟

老实说,我并没有深入到Mockito,我无法解释为什么会发生这种情况,但有一天我可能会尝试调试;-)


编辑:奇怪的是,我似乎无法用更简单的测试用例重现它。这里似乎有比看上去更多的东西。

是您的
包含
eq
都来自
Mockito
,因为即使是
hamcrest
也有这两个。我想问题可能是您在
eq(…)
调用期间调用了一个模拟方法(
this.config.apidendpoint()
)。尝试简单地将完整的URL放在那里(),而不是在那里调用另一个mock,这可能会混淆Mockito,因为它依赖于mocking@FlorianSchaetz谢谢,这就是解决办法。我不认为这会发生。你能写一个anwser,这样我就可以接受它了吗?@FlorianSchaetz不应该先计算
config.apidendpoint()
然后再通过吗?因此,
eq(…)
的参数应该与此无关,如果源对象来自模拟计算或简单的字符串文字。整个问题可能归结为Mockito的某种复杂的固有状态,它阻止了这一功能的发挥。也许比我更喜欢莫基托的人能解释这一点。总有一天我会试着去调试它,以找出其他的方法。嗯,我完全明白这是怎么发生的。从调用
时调用第一个匹配器开始,您就不希望与任何其他模拟交互。这是因为当你使用matcher时,整个matcher调用的内部堆栈都会建立起来。好的,弗洛里安。要解决此问题,您可以将对
this.config.apiEndpoint()
的调用放在自己的行中,在
when
的行之前。如果您传递的参数是匹配器,并且您也发现了该匹配器的属性,那么解决方法通常非常简单,只需获取上面一行中的财产,并将其与您从中获得的财产一起传递即可。