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?

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

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:

@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 matcher seems perfect for this use case:

@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:

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?

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?

1 Answer

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

 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 argThat return type:

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

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy