Mockito Inject mock into Spy object - java

I'm writing a test case for a Class which has a 2 level of dependency injection. I use #Spy annotation for the 1 level dependency injection object, and I would like to Mock the 2nd level of injection. However, I kept getting null pointer exception on the 2nd level. Is there any way that I inject the mock into the #Spy object?
public class CarTestCase{
#Mock
private Configuration configuration;
#Spy
private Engine engine;
#InjectMocks
private Car car;
#Test
public void test(){
Mockito.when(configuration.getProperties("")).return("Something");
car.drive();
}
}
public class Car{
#Inject
private Engine engine;
public void drive(){
engine.start();
}
}
public class Engine{
#Inject
private Configuration configuration;
public void start(){
configuration.getProperties(); // null pointer exception
}
}

I've also wandered how to inject a mock into a spy.
The following approach will not work:
#Spy
#InjectMocks
private MySpy spy;
But the desired behavior can be achieved by a "hybrid" approach, when using both annotation and manual mocking. The following works perfectly:
#Mock
private NeedToBeMocked needToBeMocked;
#InjectMocks
private MySpy mySpy;
#InjectMocks
private SubjectUnderTest sut;
#BeforeMethod
public void setUp() {
mySpy = Mockito.spy(new MySpy());
MockitoAnnotations.initMocks(this);
}
(SubjectUnderTest here depends on MySpy, and MySpy in its turn depends on NeedToBeMocked).
UPD: Personally, I think that if you have to do such a magic too often, it might be a sign that there is something wrong with dependenicies between your classes and it is worth to perform a little bit of refactoring to improve your code.

The (simplest) solution that worked for me.
#InjectMocks
private MySpy spy = Mockito.spy(new MySpy());
No need for MockitoAnnotations.initMocks(this) in this case, as long as test class is annotated with #RunWith(MockitoJUnitRunner.class).

Mockito cannot perform such a tricky injections as it's not an injection framework. So, you need to refactor your code to make it more testable. It's easy done by using constructor injection:
public class Engine{
private Configuration configuration;
#Inject
public Engine(Configuration configuration) {
this.configuration = configuration;
}
........
}
public class Car{
private Engine engine;
#Inject
public Car(Engine engine) {
this.engine = engine;
}
}
In this case you have to handle the mocking and injection manually:
public class CarTestCase{
private Configuration configuration;
private Engine engine;
private Car car;
#Before
public void setUp(){
configuration = mock(Configuration.class);
engine = spy(new Engine(configuration));
car = new Car(engine);
}
#Test
public void test(){
Mockito.when(configuration.getProperties("")).return("Something");
car.drive();
}
}

I also met this issue during the unit testing with Spring boot framework, but I found one solution for using both #Spy and #InjectMocks
Previous answer from Yoory N.
#Spy
#InjectMocks
private MySpy spy;
Because InjectMocks need to have instance created, so the solution works for me is at below,
#Spy
#InjectMocks
private MySpy spy = new MySpy();

I think I just found the definitive answer. I tried Yoory approach but changed the order of the annotations :
#InjectMocks
#Spy
private MySpy spy;
I assume that Mockito first creates the mock, and adds a spy on top of that. So there is no need to instantiate the MySpy object.

Junit5 + mockito-junit-upiter-4.2.0 works well
#ExtendWith(MockitoExtension.class)
public class MyTest {
#Spy
#InjectMocks
private SomeClass spy = new SomeClass();

Related

#Spy not working when annotated on two lists

This is my PersonSeviceImpl class. Here before saving any person I want to run some validators which implements PersonValidator. And also I autowired PersonStatusChangeValidator to use in a different method.
public class PersonServiceImpl implements PersonService {
#Autowired
PersonDao personDao;
#Autowired
List<PersonStatusChangeValidator> statusChangeValidators;
#Autowired
List<PersonValidator> personValidators;
#Override
public Person save(Person person) {
for(PersonValidator validator: personValidators){
validator.validate(person);
}
personDao.save(person);
return person;
}
}
Here I am writing test to verify whether validators are called or not.
#RunWith(PowerMockRunner.class)
public class PersonServiceImplTest {
#Mock
private PersonDao personDao;
#Mock
private PersonValidator personValidator;
#Mock
private PersonStatusChangeValidator statusChangeValidator;
#Spy
private List<PersonStatusChangeValidator> statusChangeValidators = new ArrayList<>();
#Spy
private List<PersonValidator> personValidators = new ArrayList<>();
#InjectMocks
private PersonServiceImpl personService;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
personValidators.add(personValidator);
statusChangeValidators.add(statusChangeValidator);
}
#Test
public void testCreatePerson() throws Exception {
personService.save(new Person());
verify(personValidator, times(1)).validate(any(Person.class));
}
}
The problem is personValidators, statusChangeValidators are null by the time I'm running test. And when there is a single #Spy annotation in the test, it is working fine. Need some help to know where I'm doing wrong.
Your test doesn't show any mocking of statics or finals so I'm wondering why you are using #RunWith(PowerMockRunner.class)?
I have taken your code and successfully run it with just one change: replacing #RunWith(PowerMockRunner.class) with #RunWith(MockitoJUnitRunner.class).
So, unless there is some other aspect of your tests which require PowerMock then I'd suggest running your test case with MockitoJUnitRunner. If there is some aspect of your tests which require PowerMock then I'd suggest injecting the statusChangeValidators and personValidators instances with explicit constructor injection (i.e. what #JB Nizet suggested in his comment above) so that you do not have to rely on #InjectMocks.
FWIW, there's an open issue against PowerMock for this inability to apply #InjectMocks for fields with the #Spy annotation.

Injecting a String property with #InjectMocks

I have a Spring MVC #Controller with this constructor:
#Autowired
public AbcController(XyzService xyzService, #Value("${my.property}") String myProperty) {/*...*/}
I want to write a standalone unit test for this Controller:
#RunWith(MockitoJUnitRunner.class)
public class AbcControllerTest {
#Mock
private XyzService mockXyzService;
private String myProperty = "my property value";
#InjectMocks
private AbcController controllerUnderTest;
/* tests */
}
Is there any way to get #InjectMocks to inject my String property? I know I can't mock a String since it's immutable, but can I just inject a normal String here?
#InjectMocks injects a null by default in this case. #Mock understandably throws an exception if I put it on myProperty. Is there another annotation I've missed that just means "inject this exact object rather than a Mock of it"?
You can't do this with Mockito, but Apache Commons actually has a way to do this using one of its built in utilities. You can put this in a function in JUnit that is run after Mockito injects the rest of the mocks but before your test cases run, like this:
#InjectMocks
MyClass myClass;
#Before
public void before() throws Exception {
FieldUtils.writeField(myClass, "fieldName", fieldValue, true);
}
Since you're using Spring, you can use the org.springframework.test.util.ReflectionTestUtils from the spring-test module. It neatly wraps setting a field on a object or a static field on a class (along with other utility methods).
#RunWith(MockitoJUnitRunner.class)
public class AbcControllerTest {
#Mock
private XyzService mockXyzService;
#InjectMocks
private AbcController controllerUnderTest;
#Before
public void setUp() {
ReflectionTestUtils.setField(controllerUnderTest, "myProperty",
"String you want to inject");
}
/* tests */
}
You cannot do this with Mockito, because, as you mentioned yourself, a String is final and cannot be mocked.
There is a #Spy annotation which works on real objects, but it has the same limitations as #Mock, thus you cannot spy on a String.
There is no annotation to tell Mockito to just inject that value without doing any mocking or spying. It would be a good feature, though. Perhaps suggest it at the Mockito Github repository.
You will have to manually instantiate your controller if you don't want to change your code.
The only way to have a pure annotation based test is to refactor the controller. It can use a custom object that just contains that one property, or perhaps a configuration class with multiple properties.
#Component
public class MyProperty {
#Value("${my.property}")
private String myProperty;
...
}
This can be injected into the controller.
#Autowired
public AbcController(XyzService xyzService, MyProperty myProperty) {
...
}
You can mock and inject this then.
#RunWith(MockitoJUnitRunner.class)
public class AbcControllerTest {
#Mock
private XyzService mockXyzService;
#Mock
private MyProperty myProperty;
#InjectMocks
private AbcController controllerUnderTest;
#Before
public void setUp(){
when(myProperty.get()).thenReturn("my property value");
}
/* tests */
}
This is not pretty straight forward, but at least you will be able to have a pure annotation based test with a little bit of stubbing.
Just don't use #InjectMocks in that case.
do:
#Before
public void setup() {
controllerUnderTest = new AbcController(mockXyzService, "my property value");
}
Solution is simple: You should put constructor injection for the object type while for primitive/final dependencies you can simply use setter injection and that'll be fine for this scenario.
So this:
public AbcController(XyzService xyzService, #Value("${my.property}") String myProperty) {/*...*/}
Would be changed to:
#Autowired
public AbcController(XyzService xyzService) {/*...*/}
#Autowired
public setMyProperty(#Value("${my.property}") String myProperty){/*...*/}
And the #Mock injections in test would be as simple as:
#Mock
private XyzService xyzService;
#InjectMocks
private AbcController abcController;
#BeforeMethod
public void setup(){
MockitoAnnotations.initMocks(this);
abcController.setMyProperty("new property");
}
And that'll be enough. Going for Reflections is not advisable!
PLEASE AVOID THE USAGE OF REFLECTIONS IN PRODUCTION CODE AS MUCH AS POSSIBLE!!
For the solution of Jan Groot I must remind you that it will become very nasty since you will have to remove all the #Mock and even #InjectMocks and would have to initialize and then inject them manually which for 2 dependencies sound easy but for 7 dependencies the code becomes a nightmare (see below).
private XyzService xyzService;
private AbcController abcController;
#BeforeMethod
public void setup(){ // NIGHTMARE WHEN MORE DEPENDENCIES ARE MOCKED!
xyzService = Mockito.mock(XyzService.class);
abcController = new AbcController(xyzService, "new property");
}
What you can use is this :
org.mockito.internal.util.reflection.Whitebox
Refactor your "AbcController" class constructor
In your Test class "before" method, use Whitebox.setInternalState method to specify whatever string you want
#Before
public void setUp(){
Whitebox.setInternalState(controllerUnderTest, "myProperty", "The string that you want"); }
If you want to have no change in your code then use ReflectionTestUtils.setField method
How do I mock an autowired #Value field in Spring with Mockito?

EasyMock: call order on mocks created with #Mock

Is there any way to verify methods call order between mocks if they are created with #Mock annotation?
As described in documentation it can be done with a mock control. But EasyMockRule does not expose control object.
I have looked at EasyMockSupport implementation, but have not found way to force it to use one control for all injected mocks. :(
public class Test extends EasyMockSupport {
#Rule
public EasyMockRule mocks = new EasyMockRule(this);
#Mock
private SomeClass first;
#Mock
private OtherClass second;
#TestSubject
private UnderTest subject = new UnderTest ();
#Test
public void test() {
expect(first.call());
expect(second.call());
....
//Verify that calls were in order first.call(), second.call()
}
}
You are right, it is not possible. An enhancement could be to allow to set a control in the #Mock annotation. Can you please file an issue?
In your case, you will have to create the mocks manually using the same IMocksControl like explained in the documentation.

Difference between #Mock and #InjectMocks

What is the difference between #Mock and #InjectMocks in Mockito framework?
#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>.
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.
#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.
#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
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.
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).
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
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 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(){
}
}
#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 is for creating and injecting mock instances without having to call Mockito.mock manually. In this example the instance would be ClassB.
Whereas, #InjectMocks is for injecting mock fields into the tested object automatically. In this case it would be ClassA
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

How to mock a private dao variable?

I have a dao.create() call that I want to mock when testing a method.
But I am missing something as I'm still getting NPE. What is wrong here?
class MyService {
#Inject
private Dao dao;
public void myMethod() {
//..
dao.create(object);
//
}
}
How can I mock out the dao.create() call?
#RunWith(PowerMockRunner.class)
#PrepareForTest(DAO.class)
public void MyServiceTest {
#Test
public void testMyMethod() {
PowerMockito.mock(DAO.class);
MyService service = new MyService();
service.myMethod(); //NPE for dao.create()
}
}
You are not injecting the DAO. With mockito you can change your test class to use #InjectMocks and use mockito runner.
#RunWith(MockitoJUnitRunner.class)
public void MyServiceTest {
#Mock
private Dao dao;
#InjectMocks
private MyService myService;
...
}
You can read more about InjectMocks at Inject Mocks API
Simpler way is changing your injection to injection by constructor. For example, you would change MyService to
class MyService {
...
private final Dao dao;
#Inject
public MyService(Dao dao) {
this.dao = dao;
}
...
}
then your test you could simple pass the mocked DAO in setup.
...
#Mock
private Dao dao;
#Before
public void setUp() {
this.dao = mock(Dao.class);
this.service = new MyService(dao);
}
...
now you can use verify to check if create was called, like:
...
verify(dao).create(argThat(isExpectedObjectBeingCreated(object)));
}
private Matcher<?> isExpectedObjectBeingCreated(Object object) { ... }
Using injection by constructor will let your dependencies clearer to other developers and it will help when creating tests :)
You still need to set the dao field with your mock.
You can use reflection to this.
You need to inject/set the mocked object DAO in your service class.
If it is a spring based project, you may have a look # Spring Junit Testrunner
If you use new MyService() the Dao is never injected. For the Dao to be injected you need to load the MyService via an ApplicationContext (Spring) or an Injector (Guice). Like you would in your normal application.
As others have already said, you need to set the dao field in your MyService class in some fashion. I'm unsure the mechanism to allow for a compound runner on your test to use both Powermock and a DI framework runner (assuming Powermock is required), but as long as you're already using PowerMock (for reasons unclear in the given example), you could avail yourself of the Whitebox class to set the dao more manually.
public void testMyMethod() {
Dao dao = mock(Dao.class)
doNothing().when(dao).create(anyObject())); //assuming no return val for dao.create()
MyService service = new MyService();
Whitebox.setInternalState(service, "dao", dao);
service.myMethod();
}

Categories