Mockito、argThat 和 hasEntry
Mockito, argThat, and hasEntry
tl;dr: These tests don't compile because the type parameters don't match. What changes should I make to make them compile and run
correctly?
我有一些调用服务的非测试代码。它使用地图参数调用服务的激活方法。
public class Foo {
private final Service service;
public Foo(Service service) {
this.service = service;
}
public void bar() {
Map<String, ?> params = getParams();
service.activate(params);
}
private Map<String, ?> getParams() {
// something interesting goes here
}
}
我尝试测试的一些代码依赖于这样的服务:
public interface Service {
public void activate(Map<String, ?> params);
}
我想通过使用 Mockito 模拟服务并验证是否使用合理的映射调用了激活来测试此代码。以下代码有效:
@Test
public void testExactMap() {
Service mockService = mock(Service.class);
Foo foo = new Foo(mockService);
foo.bar();
Map<String, String> expectedParams = new HashMap<>();
expectedParams.put("paramName", "paramValue");
verify(service).activate(expectedParams);
}
不过,我只想测试地图是否包含一个特定条目。 Hamcrest hasEntry matcher 似乎非常适合这个用例:
@Test
public void testHasEntry() {
Service mockService = mock(Service.class);
Foo foo = new Foo(mockService);
foo.bar();
verify(mockService).activate(argThat(hasEntry("paramName", "paramValue")));
}
当我尝试这样做时,我在 IntelliJ IDEA 中收到以下错误:
Error:(31, 45) java: incompatible types: inference variable T has incompatible bounds
equality constraints: java.util.Map<? extends java.lang.String,? extends java.lang.String>
upper bounds: java.util.Map<java.lang.String,?>,java.lang.Object
这里的问题是我需要一个 Map<String, ?>
的 Mockito 匹配器,但是 hasEntry 给了我一个 Map<? extends String, ? extends String>
的匹配器。即使使用显式类型参数,我也不知道如何协调类型参数的“?扩展”部分。我应该怎么做才能解决此错误?是否有我应该使用的特定强制转换或显式类型参数?
我知道我可以为此使用 ArgumentCaptor。这真的是唯一的方法吗?使用 Hamcrest 匹配器完全可以做到这一点吗?
由于某种原因,argThat
return 类型未被推断。尝试如下所示显式转换:
Mockito.verify(foo).bar((Map<String, String>) argThat(Matchers.hasEntry("paramName", "paramValue")));
testHasEntryCast()
可以固定如下所示。请注意,强制转换 (Map<String, ?>)
是 argThat
return 类型:
@Test
public void testHasEntryCast() {
Service mockService = mock(Service.class);
Foo foo = new Foo(mockService);
foo.bar();
verify(mockService).activate((Map<String, ?>) argThat(hasEntry("paramName", "paramValue")));
}
tl;dr: These tests don't compile because the type parameters don't match. What changes should I make to make them compile and run correctly?
我有一些调用服务的非测试代码。它使用地图参数调用服务的激活方法。
public class Foo {
private final Service service;
public Foo(Service service) {
this.service = service;
}
public void bar() {
Map<String, ?> params = getParams();
service.activate(params);
}
private Map<String, ?> getParams() {
// something interesting goes here
}
}
我尝试测试的一些代码依赖于这样的服务:
public interface Service {
public void activate(Map<String, ?> params);
}
我想通过使用 Mockito 模拟服务并验证是否使用合理的映射调用了激活来测试此代码。以下代码有效:
@Test
public void testExactMap() {
Service mockService = mock(Service.class);
Foo foo = new Foo(mockService);
foo.bar();
Map<String, String> expectedParams = new HashMap<>();
expectedParams.put("paramName", "paramValue");
verify(service).activate(expectedParams);
}
不过,我只想测试地图是否包含一个特定条目。 Hamcrest hasEntry matcher 似乎非常适合这个用例:
@Test
public void testHasEntry() {
Service mockService = mock(Service.class);
Foo foo = new Foo(mockService);
foo.bar();
verify(mockService).activate(argThat(hasEntry("paramName", "paramValue")));
}
当我尝试这样做时,我在 IntelliJ IDEA 中收到以下错误:
Error:(31, 45) java: incompatible types: inference variable T has incompatible bounds
equality constraints: java.util.Map<? extends java.lang.String,? extends java.lang.String>
upper bounds: java.util.Map<java.lang.String,?>,java.lang.Object
这里的问题是我需要一个 Map<String, ?>
的 Mockito 匹配器,但是 hasEntry 给了我一个 Map<? extends String, ? extends String>
的匹配器。即使使用显式类型参数,我也不知道如何协调类型参数的“?扩展”部分。我应该怎么做才能解决此错误?是否有我应该使用的特定强制转换或显式类型参数?
我知道我可以为此使用 ArgumentCaptor。这真的是唯一的方法吗?使用 Hamcrest 匹配器完全可以做到这一点吗?
由于某种原因,argThat
return 类型未被推断。尝试如下所示显式转换:
Mockito.verify(foo).bar((Map<String, String>) argThat(Matchers.hasEntry("paramName", "paramValue")));
testHasEntryCast()
可以固定如下所示。请注意,强制转换 (Map<String, ?>)
是 argThat
return 类型:
@Test
public void testHasEntryCast() {
Service mockService = mock(Service.class);
Foo foo = new Foo(mockService);
foo.bar();
verify(mockService).activate((Map<String, ?>) argThat(hasEntry("paramName", "paramValue")));
}