2017-04-07 144 views
2

tl; dr:这些测试不编译,因为类型参数不匹配。我应该做些什么改变才能使它们正确编译并运行 ?Mockito,argThat和hasEntry

https://github.com/wesleym/matchertest

我有一些在调用服务非测试代码。它使用map参数调用服务的activate方法。

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匹配器可以吗?

回答

3

返回类型argThat由于某种原因未被推断。尝试明确铸造,如下图所示:

Mockito.verify(foo).bar((Map<String, String>) argThat(Matchers.hasEntry("paramName", "paramValue"))); 

testHasEntryCast()可以是固定的,如下图所示。请注意,投(Map<String, ?>)argThat返回类型:

@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"))); 
} 
+0

首先,我有错误的代码片断了。抱歉!现在更正。其次,这是行不通的。 Service.activate预计'Map ',但在演员中不允许使用通配符。用'Object'替换'?'也不起作用。 – Wesley

+0

你能分享包括进口的测试代码吗? – VinPro

+0

我已经在示例项目中添加了一个指向该问题的链接。 – Wesley