【问题标题】:Mockito, argThat, and hasEntryMockito、argThat 和 hasEntry
【发布时间】:2017-04-07 23:19:37
【问题描述】:

tl;dr:这些测试无法编译,因为类型参数不匹配。我应该进行哪些更改才能使它们编译和运行 正确吗?

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 模拟服务并验证是否使用合理的映射调用了 activate 来测试此代码。以下代码有效:

@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&lt;String, ?&gt; 的 Mockito 匹配器,但是 hasEntry 给了我一个 Map&lt;? extends String, ? extends String&gt; 的匹配器。即使使用显式类型参数,我也无法弄清楚如何协调类型参数的“?扩展”部分。我应该怎么做才能解决这个错误?我应该使用特定的强制转换或显式类型参数吗?

我知道我可以为此使用 ArgumentCaptor。 这真的是唯一的方法吗?使用 Hamcrest 匹配器可以实现这一点吗?

【问题讨论】:

    标签: java testing mockito hamcrest


    【解决方案1】:

    由于某种原因,未推断出 argThat 返回类型。尝试显式转换,如下所示:

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

    testHasEntryCast() 可以固定如下所示。请注意,转换 (Map&lt;String, ?&gt;) 是 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")));
    }
    

    【讨论】:

    • 首先,我输入了错误的代码 sn-p。对不起!现已更正。其次,这行不通。 Service.activate 需要Map&lt;String, ?&gt;,但在演员表中不允许使用通配符。用Object 替换? 也不起作用。
    • 我已将示例项目的链接添加到问题中。
    • 对 Map 的强制转换在 testHasEntryCast() 中放错了位置。请参阅上面我编辑的答案。
    猜你喜欢
    • 1970-01-01
    • 2022-12-29
    • 2016-06-14
    • 1970-01-01
    • 1970-01-01
    • 2021-05-09
    • 1970-01-01
    • 2020-07-29
    • 2019-05-31
    相关资源
    最近更新 更多