[java] Difference between @Mock and @InjectMocks

What is the difference between @Mock and @InjectMocks in Mockito framework?

This question is related to java unit-testing mocking mockito

The answer is


A "mocking framework", which Mockito is based on, is a framework that gives you the ability to create Mock objects ( in old terms these objects could be called shunts, as they work as shunts for dependend functionality ) In other words, a mock object is used to imitate the real object your code is dependend on, you create a proxy object with the mocking framework. By using mock objects in your tests you are essentially going from normal unit testing to integrational testing

Mockito is an open source testing framework for Java released under the MIT License, it is a "mocking framework", that lets you write beautiful tests with clean and simple API. There are many different mocking frameworks in the Java space, however there are essentially two main types of mock object frameworks, ones that are implemented via proxy and ones that are implemented via class remapping.

Dependency injection frameworks like Spring allow you to inject your proxy objects without modifying any code, the mock object expects a certain method to be called and it will return an expected result.

The @InjectMocks annotation tries to instantiate the testing object instance and injects fields annotated with @Mock or @Spy into private fields of the testing object.

MockitoAnnotations.initMocks(this) call, resets testing object and re-initializes mocks, so remember to have this at your @Before / @BeforeMethod annotation.


  • @Mock creates a mock implementation for the classes you need.
  • @InjectMock creates an instance of the class and injects the mocks that are marked with the annotations @Mock into it.

For example

@Mock
StudentDao studentDao;

@InjectMocks
StudentService service;

@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
}

Here we need the DAO class for the service class. So, we mock it and inject it in the service class instance. Similarly, in Spring framework all the @Autowired beans can be mocked by @Mock in jUnits and injected into your bean through @InjectMocks.

MockitoAnnotations.initMocks(this) method initialises these mocks and injects them for every test method so it needs to be called in the setUp() method.

This link has a good tutorial for Mockito framework


@InjectMocks annotation can be used to inject mock fields into a test object automatically.

In below example @InjectMocks has used to inject the mock dataMap into the dataLibrary .

@Mock
Map<String, String> dataMap ;

@InjectMocks
DataLibrary dataLibrary = new DataLibrary();


    @Test
    public void whenUseInjectMocksAnnotation_() {
        Mockito.when(dataMap .get("aData")).thenReturn("aMeaning");

        assertEquals("aMeaning", dataLibrary .getMeaning("aData"));
    }

Many people have given a great explanation here about @Mock vs @InjectMocks. I like it, but I think our tests and application should be written in such a way that we shouldn't need to use @InjectMocks.

Reference for further reading with examples: https://tedvinke.wordpress.com/2014/02/13/mockito-why-you-should-not-use-injectmocks-annotation-to-autowire-fields/


@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) or Mockito.initMocks(this) 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...

}

This is a sample code on how @Mock and @InjectMocks works.

Say we have Game and Player class.

class Game {

    private Player player;

    public Game(Player player) {
        this.player = player;
    }

    public String attack() {
        return "Player attack with: " + player.getWeapon();
    }

}

class Player {

    private String weapon;

    public Player(String weapon) {
        this.weapon = weapon;
    }

    String getWeapon() {
        return weapon;
    }
}

As you see, Game class need Player to perform an attack.

@RunWith(MockitoJUnitRunner.class)
class GameTest {

    @Mock
    Player player;

    @InjectMocks
    Game game;

    @Test
    public void attackWithSwordTest() throws Exception {
        Mockito.when(player.getWeapon()).thenReturn("Sword");

        assertEquals("Player attack with: Sword", game.attack());
    }

}

Mockito will mock a Player class and it's behaviour using when and thenReturn method. Lastly, using @InjectMocks Mockito will put that Player into Game.

Notice that you don't even have to create a new Game object. Mockito will inject it for you.

// you don't have to do this
Game game = new Game(player);

We will also get same behaviour using @Spy annotation. Even if the attribute name is different.

@RunWith(MockitoJUnitRunner.class)
public class GameTest {

  @Mock Player player;

  @Spy List<String> enemies = new ArrayList<>();

  @InjectMocks Game game;

  @Test public void attackWithSwordTest() throws Exception {
    Mockito.when(player.getWeapon()).thenReturn("Sword");

    enemies.add("Dragon");
    enemies.add("Orc");

    assertEquals(2, game.numberOfEnemies());

    assertEquals("Player attack with: Sword", game.attack());
  }
}

class Game {

  private Player player;

  private List<String> opponents;

  public Game(Player player, List<String> opponents) {
    this.player = player;
    this.opponents = opponents;
  }

  public int numberOfEnemies() {
    return opponents.size();
  }

  // ...

That's because Mockito will check the Type Signature of Game class, which is Player and List<String>.


@Mock is used to declare/mock the references of the dependent beans, while @InjectMocks is used to mock the bean for which test is being created.

For example:

public class A{

   public class B b;

   public void doSomething(){

   }

}

test for class A:

public class TestClassA{

   @Mocks
   public class B b;

   @InjectMocks
   public class A a;

   @Test
   public testDoSomething(){

   }

}

In your test class, the tested class should be annotated with @InjectMocks. This tells Mockito which class to inject mocks into:

@InjectMocks
private SomeManager someManager;

From then on, we can specify which specific methods or objects inside the class, in this case, SomeManager, will be substituted with mocks:

@Mock
private SomeDependency someDependency;

In this example, SomeDependency inside the SomeManager class will be mocked.


Though the above answers have covered, I have just tried to add minute detail s which i see missing. The reason behind them(The Why).

enter image description here


Illustration:

Sample.java
---------------
    public class Sample{
        DependencyOne dependencyOne;
        DependencyTwo dependencyTwo;


        public SampleResponse methodOfSample(){
            dependencyOne.methodOne();
            dependencyTwo.methodTwo();

            ...

            return sampleResponse;
        }
    }

SampleTest.java
-----------------------
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassA.class})
public class SampleTest{

    @InjectMocks
    Sample sample;

    @Mock
    DependencyOne dependencyOne;

    @Mock
    DependencyTwo dependencyTwo;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    public void sampleMethod1_Test(){
        //Arrange the dependencies
        DependencyResponse dependencyOneResponse = Mock(sampleResponse.class);
        Mockito.doReturn(dependencyOneResponse).when(dependencyOne).methodOne();

        DependencyResponse dependencyTwoResponse = Mock(sampleResponse.class);
        Mockito.doReturn(dependencyOneResponse).when(dependencyTwo).methodTwo();

        //call the method to be tested
        SampleResponse sampleResponse = sample.methodOfSample() 

        //Assert
        <assert the SampleResponse here>
    }
}

Reference


Notice that that @InjectMocks are about to be deprecated

deprecate @InjectMocks and schedule for removal in Mockito 3/4

and you can follow @avp answer and link on:

Why You Should Not Use InjectMocks Annotation to Autowire Fields


One advantage you get with the approach mentioned by @Tom is that you don't have to create any constructors in the SomeManager, and hence limiting the clients to instantiate it.

@RunWith(MockitoJUnitRunner.class)
public class SomeManagerTest {

    @InjectMocks
    private SomeManager someManager;

    @Mock
    private SomeDependency someDependency; // this will be injected into someManager

    //You don't need to instantiate the SomeManager with default contructor at all
   //SomeManager someManager = new SomeManager();    
   //Or SomeManager someManager = new SomeManager(someDependency);

     //tests...

}

Whether its a good practice or not depends on your application design.


@Mock annotation mocks the concerned object.

@InjectMocks annotation allows to inject into the underlying object the different (and relevant) mocks created by @Mock.

Both are complementary.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to unit-testing

Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0 How to test the type of a thrown exception in Jest Unit Tests not discovered in Visual Studio 2017 Class Not Found: Empty Test Suite in IntelliJ Angular 2 Unit Tests: Cannot find name 'describe' Enzyme - How to access and set <input> value? Mocking HttpClient in unit tests Example of Mockito's argumentCaptor How to write unit testing for Angular / TypeScript for private methods with Jasmine Why is the Visual Studio 2015/2017/2019 Test Runner not discovering my xUnit v2 tests

Examples related to mocking

How can I mock the JavaScript window object using Jest? How can I mock an ES6 module import using Jest? Mocking a function to raise an Exception to test an except block Unfinished Stubbing Detected in Mockito Python mock multiple return values How do I mock a service that returns promise in AngularJS Jasmine unit test? How do Mockito matchers work? Mocking static methods with Mockito How to spyOn a value property (rather than a method) with Jasmine How do I mock a class without an interface?

Examples related to mockito

How to resolve Unneccessary Stubbing exception How do I mock a REST template exchange? Mockito : doAnswer Vs thenReturn Example of Mockito's argumentCaptor Mockito: Mock private field initialization Mockito - NullpointerException when stubbing Method Usages of doThrow() doAnswer() doNothing() and doReturn() in mockito Java verify void method calls n times with Mockito Unfinished Stubbing Detected in Mockito How do I mock an autowired @Value field in Spring with Mockito?