Below is a simple class which uses stub for Testing

  1. Below is a simple business implementation class which EmployeeDetailsImpl which uses EmployeeService API methods
  2. Now to test EmployeeDetailsImpl we need to substitude the methods in service class with stub methods for which we create EmployeeServiceStub
  3. EmployeeServiceStub is a stub class which implements the EmployeeService and provide method definitions
  4. EmployeeDetailsImplTest is the test class for EmployeeDetailsImpl which performs the unittest for methods in EmployeeDetailsImpl

EmployeeService.java

 
import java.util.List;

public interface EmployeeService {
    public List<String> GetEmployeeDetails();
}

EmployeeDetailsImpl.java

 
import com.mugil.org.api.EmployeeService;

import java.util.List;

public class EmployeeDetailsImpl {
    EmployeeService employeeService;

    public EmployeeDetailsImpl(EmployeeService pEmployeeService){
        this.employeeService = pEmployeeService;
    }

    public List<String> getEmployeeList(){
        List<String> arrEmp = this.employeeService.GetEmployeeDetails();
        return arrEmp;
    }
}

EmployeeServiceStub.java

 
import java.util.Arrays;
import java.util.List;

public class EmployeeServiceStub  implements  EmployeeService{

    @Override
    public List<String> GetEmployeeDetails() {
        return Arrays.asList("Mugil", "Mani", "Vinu");
    }
}

EmployeeDetailsImplTest.java

 
import com.mugil.org.api.EmployeeServiceStub;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class EmployeeDetailsImplTest {
    @Test
    public void getEmployeeList_success(){
        EmployeeServiceStub employeeService = new  EmployeeServiceStub();
        EmployeeDetailsImpl employeeDetailsImpl = new EmployeeDetailsImpl(employeeService);
        assertEquals(3, employeeDetailsImpl.getEmployeeList().size());
    }
}

Dis-advantage of the above implementation

  1. In the above implementation when ever new method is added to the API interface, it should be added to the EmployeeServiceStub which implements EmployeeService
  2. EmployeeServiceStub is extra java file which should be taken care, incase there are multiple services used in class multiple service stub needs to be created

Replacing stub with mocks
In the below code, the same stub service(EmployeeServiceStub.java) is replaced with mock class and its methods are replaced using when and return.This prevents the need for another class

EmployeeDetailsImplTest.java

 
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class EmployeeDetailsImplTest {
    @Test
    public void getEmployeeList_success(){
     
        //Replacement code for Stub class
        EmployeeService employeeService = mock(EmployeeService.class);
        when(employeeService.GetEmployeeDetails()).thenReturn(Arrays.asList("Mugil", "Mani", "Vinu"));

        EmployeeDetailsImpl employeeDetailsImpl = new EmployeeDetailsImpl(employeeService);
        assertEquals(3, employeeDetailsImpl.getEmployeeList().size());
    }
}

In the below code we are going to mock the List Interface and override the method behaviour of List Methods
Methods mocked

  1. get(index)
  2. size()
  3. exception

ListTest.java

package com.mugil.org;

import org.junit.Before;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.junit.Assert.assertEquals;

public class ListTest {
    List arrEmployee;

    @Before
    public void init(){
        arrEmployee = mock(List.class);
    }

    @Test
    public void ListMock_SizeMethod(){
        when(arrEmployee.size()).thenReturn(3);
        assertEquals(3, arrEmployee.size());
    }

    @Test
    public void ListMock_GetMethod(){
        when(arrEmployee.get(0)).thenReturn("Employee1");
        when(arrEmployee.get(1)).thenReturn("Employee2");
        when(arrEmployee.get(2)).thenReturn("Employee3");

        assertEquals("Employee2", arrEmployee.get(1));
        assertNotEquals(null, arrEmployee.get(2));
    }

    @Test(expected = RuntimeException.class)
    public void ListMock_ThrowException(){
        when(arrEmployee.get(anyInt())).thenThrow(new RuntimeException());
        arrEmployee.get(1);
    }
}

Junit 5 = Platform + Jupiter + Vintage 
  1. Platform = Engine + Runner + Launcher
  2. All the Class files needed for Coding Test Cases
  3. Provides Support for Junit3 and 4

Adding Dependency in pom.xml for Junit 5

JUnit 5 Platform
includes junit-jupiter-api + junit-platform-engine

<dependencies>
    [...]
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.4.0</version>
        <scope>test</scope>
    </dependency>
    [...]
</dependencies>

If you want to write and execute JUnit 3 or 4 tests via the JUnit Platform add the Vintage Engine to the dependencies

<dependencies>
    [...]
    <dependency>
        <groupId>org.junit.vintage</groupId>
        <artifactId>junit-vintage-engine</artifactId>
        <version>5.4.0</version>
        <scope>test</scope>
    </dependency>
    [...]
</dependencies>
  1. @BeforeAll, @AfterAll – Runs Before and After Class and should be static
  2. @DisplayName – Displays description about the Test Method
  3. @Disabled – @Ignore in Junit 4. Disables the Test Method
  4. @Nested – Helps in grouping of similar test methods together
  5. @ParameterizedTest – Supplying more than one input for same method in row using array
  6. @ValueSource – Provides multiple paramters to same test method for ParameterizedTest
  7. @CsvSource – Provides multiple paramters to same test method for ParameterizedTest in Key Value Pair. Key is Input and Value is expected Output

AccountUtils.java

import java.io.IOException;

public class AccountUtils {

    public boolean validateAccountId(String acctNo) throws IOException {
        if (getAccountIDLength(acctNo)) {
            return true;
        } else {
            throw new IOException("Account ID is Invalid");
        }
    }

    public boolean getAccountIDLength(String acctNo)
    {
        if(acctNo.length() < 5) return false;
        if(acctNo.length() > 10) return false;
        if(!acctNo.contains("-")) return false;

        return true;
    }

    public  String getFormattedAccID(String accountNo){
        return accountNo.toUpperCase();
    }

    public String[] getBankDetails(String accountNo){
        String[] arrAccountDetails = accountNo.split("-");
        return arrAccountDetails;
    }
}

AccountUtilsTest.java

import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;

import java.io.IOException;

import static org.junit.jupiter.api.Assertions.fail;

public class AccountUtilsTest {

    AccountUtils systemUnderTest = new AccountUtils();

    @BeforeAll
    static void init(){
        System.out.println("Initilize connection to Database");
    }

    @AfterAll
    static void destroy(){
        System.out.println("Deallocate connection to Database");
    }

    @Test
    @DisplayName("AccountID Length Validation Success")
    void test_getAccountIDLength_Success(){
        boolean expectedOutput = true;
        boolean actualOutput = systemUnderTest.getAccountIDLength("SBI-104526");

        Assertions.assertEquals(expectedOutput, actualOutput);
        Assertions.assertTrue(actualOutput);
    }

    @Test
    @Disabled
    void test_validateAccountId_Success() throws IOException {
        Assertions.assertTrue(systemUnderTest.validateAccountId("SBI-104526"));
    }

    @Test
    @DisplayName("AccountID is Invalid ")
    void test_validateAccountId_Exception(){
        Assertions.assertThrows(IOException.class, ()->{
            systemUnderTest.validateAccountId("");
        });
    }

    @Test
    @DisplayName("Account Bank Details Validation")
    void test_AccountIDForBankName_Success(){
        String[] expectedOutput = new String[]{"SBI", "104526"};
        String[] actualOutput = systemUnderTest.getBankDetails("SBI-104526");

        Assertions.assertArrayEquals(expectedOutput, actualOutput);
    }

    @Nested
    class checkValidAccountId
    {
        @ParameterizedTest
        @ValueSource(strings={"SBI", "SBI-123456789", " ", ""})
        @DisplayName("Parameterized Test AccountID Length Validation Failiure")
        void test_getAccountIDLength_Failiure(String accountId){
            Assertions.assertFalse(systemUnderTest.getAccountIDLength(accountId));
        }

        @ParameterizedTest(name="AccountID {0} formatted to {1}")
        @CsvSource(value={"sbi-123456, SBI-123456", "cbi-123456, CBI-123456"})
        @DisplayName("AccountID Format Validation")
        void getFormattedAccID_Success(String inputString, String expectedOutput){
            Assertions.assertEquals(expectedOutput, systemUnderTest.getFormattedAccID(inputString));
        }
    }
}

What is BDD?

  Given some preconditions (Arrange) -> When an action occurs (Act) -> Then verify the output (Assert)

I.E.

  Given three items in Cart
  When one Item is deleted
  Then Two items should be left in Cart
@ExtendWith(MockitoExtension.class)
public class EmpServiceImplTest {

    @Mock
    EmployeeDB employeeDB;

    @InjectMocks
    EmpServiceImpl empServiceImpl;

    @Test
    @DisplayName("Check Employee in BDD Style")
    public void test_getEmployees_Success(){
        //Given - Employee List has only one row with List size as 1
        //When  - New Employee is added to the List
        //Then  -  Employee List should contain two rows

        //Given - Employee List has 3 Employees with List size as 3
        List<Employee> arrEmployees = new ArrayList<>();
        arrEmployees.add(new Employee("101", "Mugil"));
        arrEmployees.add(new Employee("102", "Max"));
        arrEmployees.add(new Employee("103", "Mani"));

        given(employeeDB.getEmployeesFromDB()).willReturn(arrEmployees);

        //When
        List<Employee> arrFilteredEmps = empServiceImpl.getEmployees();

        //Then - there should 3 EmployeegetEmployeeByIdFromDB
        Assertions.assertEquals(3, arrFilteredEmps.size());
    }
}
  1. What is Difference between @Injectmock and @Mock?
    @Mock creates a mock. @InjectMocks creates an instance of the class and injects the mocks that are created with the @Mock (or @Spy) annotations into this instance.
    Note you must use @RunWith(MockitoJUnitRunner.class) to initialize these mocks and inject them (JUnit 4).With JUnit 5, you must use @ExtendWith(MockitoExtension.class).

    @RunWith(MockitoJUnitRunner.class) // JUnit 4
    // @ExtendWith(MockitoExtension.class) for JUnit 5
    public class SomeManagerTest {
    
        @InjectMocks
        private SomeManager someManager;
    
        @Mock
        private SomeDependency someDependency; // this will be injected into someManager
     
         //tests...
    }
    

  2. When should I use spy vs Mock?
    Use @Mock when you want to just test the functionality externally without actually calling that method. Use @Spy when you want to test the functionality externally + internally with the very method being called. Spy is a combination of Mock(methodInterceptors) and InjectMock(Instance of class Tested).
  3. What happens when unstubbed method called?
    Mockito will return null or primitive value or empty collection
  4. Does mockito when accepts combination of specific and generic matchers?
    No. Mockito matchers should be either generic or specific.
  5. What is BDD?
    Behaviour Driven Development (Given Scenario -> When the action happens -> Then this should be the case)

    Given 3 Items in Cart ->  When One Item gets Deleted -> Then 2 Items would be in Cart
    
  6. How to Verify whether the Service or method call has been made?
    Verify is used to check whether the call to the method is done or not.

    .
    .
     Mockito.verify(employeeDB, times(1)).getEmployeeByIdFromDB("101");
     Mockito.verify(employeeDB, never()).getEmployeesFromDB();
     Mockito.verify(employeeDB, atleast(2)).getEmployeeByIdFromDB("101");
    .
    .
    
  7. How to check the arguments passed to the method?
    ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
    verify(mock).doSomething(argument.capture());
    assertEquals("John", argument.getValue().getName());
    

    (or)

    //capturing varargs:
    ArgumentCaptor<Person> varArgs = ArgumentCaptor.forClass(Person.class);
    verify(mock).varArgMethod(varArgs.capture());
    List expected = asList(new Person("John"), new Person("Jane"));
    assertEquals(expected, varArgs.getAllValues());
    
  8. @SpringBootTest vs @runwith(springrunner.class) or @ExtendWith
    Enables spring boot features like @Autowire, @MockBean etc.. during junit testing. This is used to provide a bridge between Spring Boot test features and JUnit. Whenever we are using any Spring Boot testing features in our JUnit tests, this annotation will be required.@RunWith is an old annotation from JUnit 4 to use test runners. If you’re using JUnit 5 (Jupiter), you should use @ExtendWith to use JUnit extensions

    @SpringBootTest : This annotation is used to load complete application context for end to end integration testing.The @SpringBootTest annotation can be used when we need to bootstrap the entire container. The annotation works by creating the ApplicationContext that will be utilized in our tests. So this would be the annotation used while testing bootstrap class of Spring Boot Application. load application.properties and give me all the Spring Boot goodness

    We pass list of classes as parameter to @SpringBootTest whose configs are loaded from application.properties when the application is bootstrapped.

    RestWithSpringBootApplicationTests.java

    @SpringBootTest(classes = {RestWithSpringBootApplication.class, EmployeeMgmtConfig.class})
    class RestWithSpringBootApplicationTests {
      @Test
      void contextLoads() {
      }
    }
    
  9. How Methods are mocked Internally?
    Mockito works by storing and retrieving method invocation details on mocks using method interception
    When we invoke the when() method we are in fact recalling the last registered method call from that context, In our case it is Dep2Method() is saved and returned.The recorded behaviour is played back when our test invokes the mocked method again which triggers the interceptor to recall the return value we provided.In Mockito source code, we see when method does not use the parameter methodCall. But it tries to get the OngoingStubbing from an instance of MockingProgress. This OngoingStubbing is nothing but mocking context above.

     @Test
        void doIt() {
            ClassADep1.Dep2Method();
            Mockito.when("Some Blah Blah").thenReturn("Mocked!");
            assertEquals(objTarget.doIt("Sample"), "Mocked!");
        }
    
  10. What is the difference between @ExtendWith(SpringExtension.class) and @ExtendWith(MockitoExtension.class)?
    If you want to use Spring test framework features in your tests like for example @MockBean, then you have to use @ExtendWith(SpringExtension.class). It replaces the deprecated JUnit4 @RunWith(SpringJUnit4ClassRunner.class)

    When NOT involving Spring – If you just want to involve Mockito and don’t have to involve Spring, for example, when you just want to use the @Mock / @InjectMocks annotations, then you want to use @ExtendWith(MockitoExtension.class), as it doesn’t load in a bunch of unneeded Spring stuff. It replaces the deprecated JUnit4 @RunWith(MockitoJUnitRunner.class).

  11. When to use @Extendwith and @Runwith?
    If you are using Junit version < 5, so you have to use @RunWith(SpringRunner.class) or @RunWith(MockitoJUnitRunner.class) etc.If you are using Junit version = 5, so you have to use @ExtendWith(SpringExtension.class) or @ExtendWith(MockitoExtension.class) Junit4 uses *Runner.class in annotation with @RunWith

    SpringRunner.class and MockitoJunitRunner.class for Junit4
    SpringExtension.class and MockitoExtension.class for Junit5
    

Below we have a Student class with Private Class Variable(id and name), Service and Private Methods.

Student.java

public class Student {
    private Integer id;
    private String name;

    @Autowired
    private StudentService studentService;

    private String getStudentDetails(){
      return "id: " + getId() + "; name: " + getName();
    }  
}

Mocking a Private Field
we cannot access the private field id to assign a value for testing, because there isn’t a public setter method for it.
We can then use ReflectionTestUtils.setField method to assign a value to the private member id

StudentTest.java

@Test
public void setValueWithNoSetter() {
    Student student = new Student();
    ReflectionTestUtils.setField(student, "id", 101); 
    assertTrue(student.getId().equals(101));
}

Mocking a Private Method
In a similar way we can invoke private method – getStudentDetails() as below in student class
StudentTest.java

@Test
public void whenNonPublicMethod_thenReflectionTestUtilsInvokeMethod() {
    Student student= new Student ();
    ReflectionTestUtils.setField(student, "id", 101);
    ReflectionTestUtils.setField(student, "name", "Mugil");
 
    assertTrue(ReflectionTestUtils.invokeMethod(student, "employeeToString").equals
                 ("id: 101; name: Mugil"));
}

Mocking a Private Dependencies
StudentTest.java

@Test
public void whenNonPublicMethod_thenReflectionTestUtilsInvokeMethod() 
{
   Student student = new Student();
   StudentService studService = mock(StudentService.class);
   when(studService.getStudentStatus(student.getId())).thenReturn("Active");

   ReflectionTestUtils.setField(student, "studentService", studService);

.
.
}

Below we have class – ClassA which contains the actual method – MethodA to be tested. MethodA has call to two dependent
ClassA.java

package com.mugil.org;

public class ClassA {
    public ClassADep1 dependency1;
    public ClassADep2 dependency2;

    public ClassA(ClassADep1 dependency1, ClassADep2 dependency2) {
        this.dependency1 = dependency1;
        this.dependency2 = dependency2;
    }

    public boolean MethodA(){
        System.out.println("I am going to call Dep1Method");
        dependency1.Dep1Method();

        System.out.println("I am going to call Dep2Method");
        dependency2.Dep2Method();

        return true;
    }
}

ClassADep1.java

package com.mugil.org;

public class ClassADep1 {
    public void Dep1Method(){
        System.out.println("This is ClassADep1 Method getting called");
    }
}

ClassADep2.java

package com.mugil.org;

public class ClassADep2 {
    public void Dep2Method(){
        System.out.println("This is ClassADep2 Method getting called");
    }
}

Use @Mock when you want to just test the functionality externally without actually calling that method.If you want to be safe and avoid calling external services and just want to test the logic inside of the unit, then use mock.

Using @Mock annotation for Dependency
ClassATest.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.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.*;

@ExtendWith({MockitoExtension.class})
class ClassATest {
    @InjectMocks
    ClassA classA;

    @Mock
    ClassADep1 dependency1;

    @Mock
    ClassADep2 dependency2;

    @Test
    void methodA() {
        assertEquals(true, classA.MethodA());
    }
}

Output

I am going to call Dep1Method
I am going to call Dep2Method

Use @Spy when you want to test the functionality externally + internally with the very method being called. If you want to call an external service and perform calling of real dependencies, or simply say, you want to run the program as it is and just stub specific methods, then use spy.

Using @Spy annotation for Dependency
ClassATest.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.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;

@ExtendWith({MockitoExtension.class})
class ClassATest {
    @InjectMocks
    ClassA classA;

    @Spy
    ClassADep1 dependency1;

    @Spy
    ClassADep2 dependency2;

    @Test
    void methodA() {
        assertEquals(true, classA.MethodA());
    }
}

Output

I am going to call Dep1Method
This is ClassADep1 Method getting called
I am going to call Dep2Method
This is ClassADep2 Method getting called

Below is a class StudentUtils which contains only two Method – doNothingWhenCalled and dummymethod. We are going to unit test doNothingWhenCalled method.

The conclusion would be to use @Spy when we mock methods of same class tested to doNothing and use @Mock to mock method to doNothing call to other classes.

StudentUtils.java

package com.mugil.org;

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

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

    public StudentUtils(){
        arrStudents.add(new Student("101", "Mugil"));
    }

    public Student doNothingWhenCalled()
    {
        dummymethod(new Student("102" ,"abc"));
        return new Student("103", "StudentName");
    }

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

@InjectMocks
StudentUtilsTest.java

@ExtendWith({MockitoExtension.class})
class StudentUtilsTest {
    @InjectMocks
    StudentUtils systemUnderTest;

    @Test
    void doNothingCalled() {
        Assertions.assertThat(systemUnderTest.doNothingWhenCalled()).isInstanceOf(Student.class);
    }
}

Output

Dummy Method Called

@Mocks
StudentUtilsTest.java

@ExtendWith({MockitoExtension.class})
class StudentUtilsTest {
    @InjectMocks
    StudentUtils systemUnderTest;

    @Test
    void doNothingCalled() {
        systemUnderTest = Mockito.mock(StudentUtils.class);
        Mockito.when(systemUnderTest.dummymethod(any())).thenReturn("Dummy Method");

        Assertions.assertThat(systemUnderTest.doNothingWhenCalled()).isInstanceOf(Student.class);
    }
}

You can see below we are trying to call method to be tested under empty mock instance which doesnot have default method definition. There is no point in mocking method definition since systemUnderTest.doNothingWhenCalled() would try to invoke test method which has no idea about.
Output

java.lang.AssertionError: 
Expecting actual not to be null

@Spy
StudentUtilsTest.java

@ExtendWith({MockitoExtension.class})
class StudentUtilsTest {
    @InjectMocks
    StudentUtils systemUnderTest;

    @Test
    void doNothingCalled() {
        systemUnderTest = Mockito.spy(StudentUtils.class);
        Assertions.assertThat(systemUnderTest.doNothingWhenCalled()).isInstanceOf(Student.class);
    }
}

Output

Dummy Method Called

Below is the Debug of Object created using @Mock, @InjectMock and @Spy.As you can see the one with Mock contains only MockInterceptor which does not have definition of methods on its own where as @InjectMock created instance of TestClass. @Spy contains both MockInterceptor and Instance enabling partial mock.

While Using InjectMock you can see the MockitoInterceptor in scope

While Using InjectMock you can see the class variables getting initialized

While Using Spy you can see both class variables getting initialized and MockitoInterceptor in scope

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