Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito mock object using real implementation

Tags:

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();

}
}
like image 464
nuicca Avatar asked Jul 20 '17 15:07

nuicca


People also ask

How do you call a real method on a mock object?

Mockito allows us to partially mock an object. This means that we can create a mock object and still be able to call a real method on it. To call a real method on a mocked object we use Mockito's thenCallRealMethod().

Can I mock objects in Mockito?

The Mockito. mock() method allows us to create a mock object of a class or an interface. We can then use the mock to stub return values for its methods and verify if they were called. We don't need to do anything else to this method before we can use it.

How do you mock an object in JUnit?

We can use Mockito class mock() method to create a mock object of a given class or interface. This is the simplest way to mock an object. We are using JUnit 5 to write test cases in conjunction with Mockito to mock objects.


2 Answers

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")));
like image 57
Morfic Avatar answered Nov 15 '22 13:11

Morfic


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);
like image 31
Luciano van der Veekens Avatar answered Nov 15 '22 13:11

Luciano van der Veekens