与argThat匹配只适用于具有单个参数的方法吗?

时间:2014-03-25 18:32:26

标签: java unit-testing junit mockito hamcrest

我在我的测试类中调用了以下方法:

class ClassUnderTest {
   [...]
    restTemplate.getForEntity(url, MyResponseEntity.class, parameterMap);
   [...]
}

在包含此行的类的单元测试中,我想存根getForEntity方法,以便它为parameterMap中的不同条目返回不同的响应。 使用BDDMockito,我试图通过使用argThat来匹配所需参数是parameterMap的一部分:

@InjectMocks
private ClassUnderTest classUnderTest;

@Mock
private RestTemplate restTemplate;

[...]

given(restTemplate.getForEntity(anyString(), any(Class.class), argThat(hasEntry("myKey", "myValue"))
   .willReturn(responseEntityA);

但是,如果我运行测试使parameterMap包含(我在调试器中验证了这一点)一个键“myKey”和一个值“myValue”,我得到一个NullPointerException,因为mockito似乎无法将方法调用与我创建的存根匹配。

另一方面,使用以下非常通用的匹配允许我在没有NPE的情况下运行我的测试,为所有调用提供默认响应,但它不允许我定义自定义响应给定的参数。

given(restTemplate.getForEntity(anyString(), any(Class.class), anyMap())
  .willReturn(defaultResponseEntity);

这是什么原因? argThat仅适用于具有单个参数的方法吗? 还有另一种方法可以将getEntity的调用与包含特定(键,值)对的地图进行匹配吗?

2 个答案:

答案 0 :(得分:3)

argThat肯定适用于多个参数,并且您尝试做的事情没有明显错误。我有一种唠叨的预感,它正在选择the wrong overload

getForEntity(String url, Class<T> responseType, Map<String,?> urlVariables)
getForEntity(String url, Class<T> responseType, Object... urlVariables)

如果泛型不完全匹配,Java可能会认为您的hasEntry最匹配Object...anyMap匹配的Map<String, ?>方法。在这种情况下,您将存在未调用的重载(Object...),并且Mockito将恢复为您在被测系统中实际调用的默认返回值(Map<String, ?> )。将鼠标悬停在IDE中的方法调用上可以了解编译器匹配的过载。

为了给Java提供更好的提示,请尝试使用强制转换,如下所示(警告,未经过测试或验证):

given(restTemplate.getForEntity(
         anyString(),
         any(Class.class),
         (Map<String, ?>) argThat(hasEntry("myKey", "myValue"))))
    .willReturn(responseEntityA);    

答案 1 :(得分:0)

我不确定为什么argThat不适合您,但您可以尝试使用thenAnswer并检查Answer中的参数。