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
  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