Pierre Girardeau
Pierre Girardeau

Reputation: 45

Mocking two maps in a class

I have to test a class that injects two maps with springs. I would like to mock both maps. I use the Mock notation as follows :

@Mock
private Map<String, Integer> map1;

@Mock
private Map<String, Date> map2;

but I get the following error :

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.util.Date

It seems that only the first mocked map is used for both maps.

What am I doing wrong ?

Upvotes: 3

Views: 3014

Answers (3)

Ste7
Ste7

Reputation: 119

try

@Mock
private Map map1;

@Mock
private Map map2;

instead

@Mock
private Map<String, Integer> map1;

@Mock
private Map<String, Date> map2;

Then you will just need to mock a behavior like:

when(map1).get("hello").thenReturn(25);
when(map2).get("birthday").thenReturn(new Date(2000, 07, 24));

Upvotes: 0

Sergii Bishyr
Sergii Bishyr

Reputation: 8641

As long as the type of the two fields are the same, mockito doesn't know to how to inject your mock by types. So it tries to inject it by name. In this case, looks like the name of fields in your class under test does not match to the mock object that you have created. Here is the doc for @InjectMocks:

Field injection; mocks will first be resolved by type (if a single type match injection will happen regardless of the name), then, if there is several property of the same type, by the match of the field name and the mock name.

You can either rename your filed or use explicit mock names:

@Mock(name="foo")
private Map<String, Integer> map1;

@Mock(name="bar")
private Map<String, Date> map2;

But I don't think that this is the best solution. In case if the filed name will be renamed you will got the false negative test result: functionality works correct but test fails.

For me, the best solution is to refactor your code so the class under test receive the dependencies in the constructor. After that you can mock it like this:

@Mock
private Map<String, Integer> map1;

@Mock
private Map<String, Date> map2;

private ClassUnderTets cut;

@Before
public void setUp() throws Exception {
    cut = new ClassUnderTets(map1, map2);
}

Or even:

@Mock
private Map<String, Integer> map1;

@Mock
private Map<String, Date> map2;

@InjectMocks
private ClassUnderTets cut;

As mentioned in the docs:

Constructor injection; the biggest constructor is chosen, then arguments are resolved with mocks declared in the test only

Upvotes: 3

atrunov
atrunov

Reputation: 1

Probably you have problem because you try to inject two mocks with the same interface (variable names does not match to properties for example)

Please take a look at second post from this topic for reference.

Property setter injection; mocks will first be resolved by type, then, if there is several property of the same type, by the match of the property name and the mock name.

Upvotes: 0

Related Questions