nuicca
nuicca

Reputation: 778

Mockito mock object using real implementation

Why is mockMap using the real implementation? How do I prevent this?

In method testFirstKeyMatch

when(mockMap.keySet().toArray()[0])...

throws ArrayIndexOutOfBoundsException: 0 when running the test.

MaxSizeHashMap is a LinkedHashMap with max size of 7, throws an IndexOutOfBoundsException when I attempt to put more into.

Profile keeps track of something not essential for this.

SuperClass.java

public class SuperClass {

protected String[] days;
protected MaxSizeHashMap<String, String> map;

public SuperClass() {
    days = new String[7];
    map = new MaxSizeHashMap<String, String>();
    //...
}

void updateDays() {

    cal = Calendar.getInstance();

    for (int i = 0; i < 7; i = i + 1) {

        //adds short names "Mon", "Tue", ... to days
        days[i] = cal.getDisplayName(Calendar.DAY_OF_WEEK, 
                Calendar.SHORT, Locale.US);

        cal.add(Calendar.DATE, 1);
    }
}

void firstKeyMatch(Profile profile) {

    updateDays(); 

    //checks if first key of map is not same as days[0]
    if (days[0] != map.keySet().toArray()[0]) {

        profile.add();

        //...
     }
 }
 }

SuperClassTest.java

@RunWith(MockitoJUnitRunner.class)
public class SuperClassTest {

@InjectMocks
private SuperClass spr = new SuperClass();

@Mock
private MaxSizeHashMap<String, String> mockMap;

@Mock
private Profile mockProfile;

//...

@Test
public void testFirstKeyMatch() {   

    when(mockMap.keySet().toArray()[0]).thenReturn(spr.days[0]);

    verify(mockProfile, never()).add();

}
}

Upvotes: 5

Views: 4786

Answers (2)

Morfic
Morfic

Reputation: 15508

As per the documentation, mockito's implicit behaviour for a mock is to return default values.

By default, for all methods that return a value, a mock will return either null, a primitive/primitive wrapper value, or an empty collection, as appropriate. For example 0 for an int/Integer and false for a boolean/Boolean.

In consequence, your mockMap.keySet() will return an empty hash-set, which you then convert to an empty array and try to retrieve the (non-existent) first element, hence the IOOBE.

debugger

In conclusion, mockito is not using the real implementation, but it's behaving normally as it's supposed to.

You did not post the entire constructor of SuperClass, but probably after you instantiate the map, you also populate it with values. If that's true, then one can argue that the exception is actually proof that mockito does not use the real implementation, because you'd really be getting the first element.

As for the solutions, well it's already been suggested to return your own hash set with whatever data you require (credits go to Abubakkar):

when(mockMap.keySet()).thenReturn(new HashSet(Arrays.asList("your day string")));

Upvotes: 3

Luciano van der Veekens
Luciano van der Veekens

Reputation: 6577

To redirect all mockMap.keySet().toArray()[i] calls to spr.days[i], you can tell mockMap to return the days array when someone requests the key set.

Set keySetMock = mock(Set.class);
when(keySetMock.toArray()).thenReturn(spr.days);
when(mockMap.keySet()).thenReturn(keySetMock);

Upvotes: 1

Related Questions