Mockito 3 Spy Limitations

Mockito spy provides us a great way to test our code, it can mock requests and respond just like mock objects and if required then call the real method as well which is not possible in mock objects. But it has some catch because spy is able to call real methods, it has to deal with real method issues.

unlike mock, spy dont have nice mock feature.

in below program, spy object is calling the real getApple method and appleList in getApple method doesn't have any value hence it will throw IndexOutOfBounds Exception.

package com.example.mokito3.sujan;

import java.util.ArrayList;
import java.util.List;

public class AppleService {
    List<String> appleList = new ArrayList<>();

    public String getApple(int appleIndx) {
        System.out.println("AppleService.getApple: appleIndx = " + appleIndx);
        return appleList.get(appleIndx);
    }
}
package com.example.mokito3.sujan;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
public class AppleServiceTest {
    @Spy
    private AppleService appleService;

    @Test
    void saveAppleWithMockTest() {
        when(appleService.getApple(0)).thenReturn("Macintosh");
        String appleName = appleService.getApple(0);
        Assertions.assertEquals("Macintosh", appleName);
    }
}
plugins {
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories { jcenter() }
dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
    testCompile 'org.mockito:mockito-junit-jupiter:3.4.4'
}
test {
    useJUnitPlatform()
}

Always use doReturn, Answer, Throw(), CallRealMethod method family while dealing with spy stubs.

package com.example.mokito3.sujan;

import java.util.ArrayList;
import java.util.List;

public class AppleService {
    List<String> appleList = new ArrayList<>();

    public String getApple(int appleIndx) {
        System.out.println("AppleService.getApple: appleIndx = " + appleIndx);
        return appleList.get(appleIndx);
    }
}
package com.example.mokito3.sujan;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.mockito.Mockito.doReturn;

@ExtendWith(MockitoExtension.class)
public class AppleServiceTest {
    @Spy
    private AppleService appleService;

    @Test
    void saveAppleWithMockTest() {
        doReturn("Macintosh").when(appleService).getApple(0);
        String appleName = appleService.getApple(0);
        Assertions.assertEquals("Macintosh", appleName);
    }
}
plugins {
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories { jcenter() }
dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
    testCompile 'org.mockito:mockito-junit-jupiter:3.4.4'
}
test {
    useJUnitPlatform()
}

 

Spy with final method

Mockito has a hard time with final methds, hence mockito framework doesn't mock final methods along with that we cannot verify those final methods as well.

package com.example.mokito3.sujan;

import java.util.ArrayList;
import java.util.List;

public class AppleService {
    List<String> appleList = new ArrayList<>();

    public final String getApple(int appleIndx) {
        System.out.println("AppleService.getApple: appleIndx = " + appleIndx);
        return appleList.get(appleIndx);
    }
}
package com.example.mokito3.sujan;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.mockito.Mockito.doReturn;

@ExtendWith(MockitoExtension.class)
public class AppleServiceTest {
    @Spy
    private AppleService appleService;

    @Test
    void saveAppleWithMockTest() {
        doReturn("Macintosh").when(appleService).getApple(0);
        String appleName = appleService.getApple(0);
        Assertions.assertEquals("Macintosh", appleName);
    }
}
plugins {
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories { jcenter() }
dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
    testCompile 'org.mockito:mockito-junit-jupiter:3.4.4'
}
test {
    useJUnitPlatform()
}

follow us on