java Mockito、argThat 和 hasEntry

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43288390/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 07:17:50  来源:igfitidea点击:

Mockito, argThat, and hasEntry

javatestingmockitohamcrest

提问by Wesley

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?

https://github.com/wesleym/matchertest

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

https://github.com/wesleym/matchertest

I have some non-test code that calls into a service. It calls the service's activate method with a map parameter.

我有一些调用服务的非测试代码。它使用 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
  }
}

Some code I'm trying to test has a dependency on a service like this one:

我试图测试的一些代码依赖于这样的服务:

public interface Service {
  public void activate(Map<String, ?> params);
}

I'd like to test this code by mocking the service with Mockito and verifying that activate was called with a reasonable map. The following code works:

我想通过使用 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);
}

However, I'd like to just test that the map contains one particular entry. The Hamcrest hasEntry matcherseems perfect for this use case:

但是,我只想测试地图是否包含一个特定条目。Hamcrest hasEntry 匹配器似乎非常适合这个用例:

@Test
public void testHasEntry() {
    Service mockService = mock(Service.class);
    Foo foo = new Foo(mockService);

    foo.bar();

    verify(mockService).activate(argThat(hasEntry("paramName", "paramValue")));
}

When I try this, I get the following error in IntelliJ IDEA:

当我尝试这个时,我在 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

The problem here is that I need a Mockito matcher of Map<String, ?>, but hasEntry gives me a matcher of Map<? extends String, ? extends String>. Even with explicit type parameters, I can't figure out what to do to reconcile the "? extends" part of the type parameter. What should I do to resolve this error? Is there a specific cast or explicit type parameter I should use?

这里的问题是我需要一个 Mockito 匹配器Map<String, ?>,但是 hasEntry 给了我一个Map<? extends String, ? extends String>. 即使使用显式类型参数,我也无法弄清楚如何协调类型参数的“?扩展”部分。我应该怎么做才能解决这个错误?我应该使用特定的强制转换或显式类型参数吗?

I understand that I can use ArgumentCaptor for this.Is that really the only way to do this? Is this possible at all with Hamcrest matchers?

我知道我可以为此使用 ArgumentCaptor。这真的是唯一的方法吗?对于 Hamcrest 匹配器,这完全可能吗?

回答by VinPro

The argThatreturn type is not being inferred for some reason. Try explicitly casting as shown below:

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

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

The testHasEntryCast()can be fixed as shown below. Notice that cast (Map<String, ?>)is to argThatreturn type:

所述testHasEntryCast()可固定,如下所示。注意 cast(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")));
}