How to Pass Interface or Abstract Class as Matcher?
Person.java

public interface Person {
}

StudentUtils.java

 public String methodWithInterfaceArg(Person person)
    {
        //This method takes Interface Implementation as Parameter
        Somemethod(person);
        return "Test Success";
    }

    public void Somemethod(Person p){
        System.out.println("Hello There");
    }

StudentUtilsTest.java

@Test
    @DisplayName("Test for method which takes interface as argument")
    void methodWithInterfaceArg() 
    {
        Person objPerson = Mockito.mock(Person.class);

        // Using spy we are creating a new mock and call the method to be tested
        StudentUtils studentUtils= Mockito.spy(StudentUtils.class);

        doNothing().when(studentUtils).Somemethod(objPerson);

        // While testing we should call the method to be tested using new spyObject rather than systemUnderTest
        // This is because only in the Spy object studentUtils we have created a mock definition for Somemethod
        // Hence when methodWithInterfaceArg is called using systemUnderTest the mock  definition created using spy would be lost
        assertEquals("Test Success", studentUtils.methodWithInterfaceArg(objPerson));
    }

How to doNothing when internal method which returns void is gets called?
StudentUtils.java

    public String methodWithInterfaceArg(Person person)
    {
        //This method has void return type
        Somemethod(person);
        return "Test Success";
    }

    public void Somemethod(Person p){
        System.out.println("Hello There");
    }

StudentUtilsTest.java

    @Test
    @DisplayName("Test for internal method which is of void return type")
    void methodWithInterfaceArg() {
        Person objPerson = Mockito.mock(Person.class);

        // Using spy we are creating a new mock and call the method to be tested
        StudentUtils studentUtils= Mockito.spy(StudentUtils.class);

        //With Object Created using spy we can mock the actual method to do nothing
        doNothing().when(studentUtils).Somemethod(objPerson);

        assertEquals("Test Success", studentUtils.methodWithInterfaceArg(objPerson));
    }

How to doNothing when method which returns value is called?
StudentUtils.java

public class StudentUtils {
    private List arrStudents = new ArrayList();
    private String Name = "Mugil";

    public String dummymethod(Student objStudent)
    {
        System.out.println("Dummy Method Called");
        return "Dummy Method";
    }

    public String methodCallingAnotherMethodReturningVal()
    {
        String something = dummymethod(new Student("102" ,"abc"));
        return "Dummy Method returned "+ something;
    }
}

StudentUtilsTest.java

 @Test
    @DisplayName("Test for Method calling another method which returns value")
    void methodCallingAnotherMethodReturningVal() {
        StudentUtils studentUtils= Mockito.spy(StudentUtils.class);

        Mockito.when(studentUtils.dummymethod(any())).thenReturn("Test Student");
        Assert.assertEquals("Dummy Method returned Test Student", studentUtils.methodCallingAnotherMethodReturningVal());
    }

How to mock methods of private and public instance class variables?

  1. The below scenario we are going to mock instance of method which belongs to other class initialized over by public and private class variables
  2. We Create a new mock and initialize using reflectionUtils for the objDBConnectionFactory which is private whereas we use a spy to directly change the method definition of objDBConnectionFactory2

DBConnectionFactory.java

package com.mugil.org;

public class DBConnectionFactory {
    public DBConnectionFactory() {
    }

    public <T> T  readDetails(byte[] src, Class<People> valueType){
        return (T)new Student();
    }

    public <T> T  readDetails2(String src){
        return (T)new Student();
    }
}

MockPrivateFileds.java

package com.mugil.org;

import org.springframework.web.client.HttpStatusCodeException;

public class MockPrivateFileds {
    private DBConnectionFactory objDBConnectionFactory = new DBConnectionFactory();

    public DBConnectionFactory objDBConnectionFactory2 = new DBConnectionFactory();

    private Student getDetails(HttpStatusCodeException httpStatusCodeException) {
        return objDBConnectionFactory.readDetails(httpStatusCodeException.getResponseBodyAsByteArray(), People.class);
    }

    public Student getDetails2(HttpStatusCodeException httpStatusCodeException) {
        return objDBConnectionFactory2.readDetails2("String");
    }
}

MockPrivateFiledsTest.java

package com.mugil.org;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.client.HttpStatusCodeException;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.mockito.ArgumentMatchers.*;

@ExtendWith({MockitoExtension.class})
class MockPrivateFiledsTest {
    @InjectMocks
    MockPrivateFileds systemUnderTest;

    @Test
    void getDetailsTest() {
        HttpStatusCodeException httpStatusCodeException = Mockito.mock(HttpStatusCodeException.class);

        /*The Below two lines of code are needed because the objDBConnectionFactory created doesnot contain any definition of methods
        * So the definition could be set by creating new mock object as below. If there is Setter we can use setter to set the newly created mock object
        * Since there is no setter and its private we are going to use reflectionUtils */
        DBConnectionFactory dbConnectionFactory = Mockito.mock(DBConnectionFactory.class);
        ReflectionTestUtils.setField(systemUnderTest, "objDBConnectionFactory", dbConnectionFactory);
        Mockito.when(dbConnectionFactory.readDetails(nullable(byte[].class), eq(People.class))).thenReturn(new Student());

        assertThat(ReflectionTestUtils.invokeMethod(systemUnderTest, "getDetails", httpStatusCodeException), instanceOf(Student.class));
    }

    @Test
    void getDetailsTest2() {
        HttpStatusCodeException httpStatusCodeException = Mockito.mock(HttpStatusCodeException.class);
        systemUnderTest = Mockito.spy(MockPrivateFileds.class);

        DBConnectionFactory dbConnectionFactory2 = Mockito.spy(DBConnectionFactory.class);
        ReflectionTestUtils.setField(systemUnderTest, "objDBConnectionFactory2", dbConnectionFactory2);

        /*Below is a mocking of a public method through its instance by using spy. The below case is similar to above
        * scenario with the only difference we can use spy to gain access to readDetails2 */
        Mockito.when(systemUnderTest.objDBConnectionFactory2.readDetails2(anyString())).thenReturn(new Student());

        assertThat(systemUnderTest.getDetails2(httpStatusCodeException), instanceOf(Student.class));
    }
}

Comments are closed.