Difference between @Mock and @InjectMocks

JavaUnit TestingMockingMockito

Java Problem Overview


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

Java Solutions


Solution 1 - Java

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

}

Solution 2 - Java

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

Solution 3 - Java

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.

Solution 4 - Java

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

Solution 5 - Java

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

Solution 6 - Java

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.

Solution 7 - Java

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

Solution 8 - Java

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.

Solution 9 - Java

@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(){
   
   }

}

Solution 10 - Java

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

Solution 11 - Java

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/

Solution 12 - Java

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser2249972View Question on Stackoverflow
Solution 1 - JavaTom VerelstView Answer on Stackoverflow
Solution 2 - JavaaldokView Answer on Stackoverflow
Solution 3 - Javauser2989087View Answer on Stackoverflow
Solution 4 - JavaMik378View Answer on Stackoverflow
Solution 5 - JavaSana JahanView Answer on Stackoverflow
Solution 6 - JavaserupView Answer on Stackoverflow
Solution 7 - JavaAngelin NadarView Answer on Stackoverflow
Solution 8 - JavatintinView Answer on Stackoverflow
Solution 9 - Javadev_2014View Answer on Stackoverflow
Solution 10 - JavaLahiru WijesekaraView Answer on Stackoverflow
Solution 11 - JavaavpView Answer on Stackoverflow
Solution 12 - Javauser7294900View Answer on Stackoverflow