Null after #InjectMocks - java

I am having some troubles passing a dependency while unit testing with JUnit.
Consider these pieces of code:
This is the dependacy injecton into the class which i want to test, lets call it Controller.
#Inject private FastPowering fastPowering;
And this is the unit test:
#RunWith(MockitoJUnitRunner.class)
public class ControllerTest {
#Mock
FastPowering fastPower;
#InjectMocks
Controller controller;
#Test
public void test() {
assertEquals(
(controller.computeAnswer(new BigDecimal(2), 2)).longValue(),
(long) Math.pow(2, 2));
}
}
It seems that fastPower is null, please explain how to fix that.
Null pointer exception , because of calling the #injected field (fastPower) inside the .computeAnswer method)
Edit:
Solved i should have read about the difference between #Mock and #Spy...
Due to a lot of comments I am adding some more context to the solution
The difference is that in mock, you are creating a complete mock or fake object while in spy, there is the real object and you just spying or stubbing specific methods of it. While in spy objects, of course, since it is a real method, when you are not stubbing the method, then it will call the real method behavior.
If fastPower is annotated as #Mock it's methods are dummy, yet controller.computeAnswer depends on them to compute. One must provide behaviour.
If spy is used without stubbing then the real implementation of fastPower is being executed which eventually returns desired value.
Another option is to use a real FastPowering instance
https://github.com/mockito/mockito/wiki/Using-Spies-(and-Fakes)
https://github.com/mockito/mockito/wiki/Mocking-Object-Creation
And some stackoverflow thread outlining the difference Mocking vs. Spying in mocking frameworks
Short Answer: Replace #Mock with #Spy and should be working fine

Use MockitoAnnotations.initMocks to initiate the #Mock and #InjectMocks objects. Your test would look something like:
#Mock
FastPowering fastPower;
#InjectMocks
Controller controller;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
....
}

After debugging I found a reason. This is because of the org.powermock.core.MockRepository#instanceMocks collection. It doesn't contain a mock for a field with #InjectMocks annotation (Controller controller in your case).
To solve it try to use the #Spy annotation in the field declaration with initializing of them and #PrepareForTest above the class declaration:
#PrepareForTest(Controller.class)
#RunWith(MockitoJUnitRunner.class)
public class ControllerTest {
#Mock
FastPowering fastPower;
#Spy
#InjectMocks
Controller controller = new Controller();
#Test
public void test() {
//...
}
}
In my case it helped. Using of the Mockitoannotations.initMocks(this) method is not required, it doesn't affect the result.

I fixed this by removing the extraneous new instance I was creating in my #Before method (see example below). It was also fixed by moving MockitoAnnotations.initMocks(this) after initializing myClass, but since Mockito created myClass anyway, that solution was inferior.
// Note - you may need #mock(name="foo") to help mockito differentiate props
// if they have the same type
#mock
private Thing something;
#InjectMocks
private MyClass myClass;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this); // Moving this below the next line fixed it...
myClass = new MyClass() // But just remove this line and let Mockito do the work
}

Useful to note that the use of MockitoAnnotations.initMocks(this); needs to come at the end of your #Before/setUp() method.
If it is at the top of your setUp() then it may cause other mocked classes to not be initialised.
I ran into this error myself just now and placing .initMocks at the end of my #Before solved my issue.

I was using the wrong #Test annotations, If you want to use #InjectMocks and #Mock in your Mockito Test, then you should
add #ExtendWith(MockitoExtension.class) annotation on your test class
annotate your test methods with #Test (org.junit.jupiter.api.Test) and not the #Test (org.junit.Test) annotation. be careful with the import that you are using for this annotation.
This works on mockito-core:3.6.28

2 more things to check:
1. Mocking the behaviours of fastPower. What should this mocked object return, when it methods are called? i.e. when(fastPower.doSomething()).thenReturn(some_kind_of_object);
2. Check if the controller.computeAnswer() does not return NULL for the input of new BigDecimal(2), 2)).longValue(), (long) Math.pow(2, 2).

Related

How is it possible to initialize the Junit5 Mocks annotated with #Mock before each test using MockitoExtension?

I would like to create some Junit test using the annotation #Mock and MockitoExtension.
Something like this:
#ExtendWith(MockitoExtension.class)
public class Test {
#Mock
MyObject mock;
#Test
public void test1() {
..
}
#Test
public void test2() {
..
}
How can I tell to MockitoExtension that it has to create the mock before each test execution to isolate them?
I would like to avoid that the first executed test defining a behavior for the mock with when(mock.doSomething()).then(returnSomething()) will not influence the other tests by resetting the mock)
It's not just Mockito that is reinitialized, it's standard JUnit behavior. A new instance of your Test class is created for each method. So this creates isolation between each test for anything you set up as instance members, including Mockito instances.
You can imagine your test is run like this:
Test instance1 = new Test();
instance1.test1();
Test instance2 = new Test();
instance2.test2();
You can set behavior for each instance using #BeforeEach:
#BeforeEach
void setUp() {
// this runs for every test method on a brand new scope
}
notice how it is an instance method.
If you do want "global" behavior, you use static methods and variables instead. The corresponding annotations are #BeforeAll/#AfterAll which must be applied to static methods and runs once each for the whole class.

About #InjectMocks and #Mock

I want to test requestListServiceImpl this class.It contains requestListDao.
RequestListServiceImpl Code
#Override
public PageInfo<RequestList> getAllRequest(int startPage, int pageSize, String accountName,String userName) {
PageHelper.startPage(startPage, pageSize);
List<RequestList> list=requestListDao.getAllRequest(accountName,userName);
for(RequestList requestList:list) {
switch (requestList.getStatus()) {
case "0":
requestList.setStatus("Waiting");
break;
case "1":
requestList.setStatus("Closed");
break;
case "2":
requestList.setStatus("Cancel");
break;
default:
requestList.setStatus("NAN");
break;
}
}
PageInfo<RequestList> pageInfo = new PageInfo<RequestList>(list);
return pageInfo;
}
#Override
public void createRequest(RequestList requestList) {
Integer coount=requestListDao.getTime(requestList.getCreateName());
// AWSSnsUtil.sendMassageToSns(requestList.getAccountName());
requestList.setTime(++coount);
requestListDao.createRequest(requestList);
}
Test Code:
#InjectMocks
RequestListServiceImpl requestListServiceImpl;
#Mock
RequestListDao requestListDao;
#Before
public void setup(){
MockitoAnnotations.openMocks(this);
}
#Test //it's ok
public void testGetAllRequest() throws Exception {
RequestList r=new RequestList();
r.setStatus("0");
when(requestListDao.getAllRequest(anyString(), anyString())).thenReturn(Arrays.<RequestList>asList(r));
PageInfo<RequestList> res=requestListServiceImpl.getAllRequest(1,1,"1","1");
Assert.assertNotNull(res);
}
#Test //this test is error, the error is requestListServiceImpl is not mock.
public void testCreateRequest() throws Exception {
when(requestListDao.getTime(anyString())).thenReturn(0);
RequestList r=new RequestList();
r.setCreateName("demo");
requestListServiceImpl.createRequest(r);
verify(requestListServiceImpl).createRequest(r);
}
Error info
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type RequestListServiceImpl and is not a mock!
Make sure you place the parenthesis correctly!
See the examples of correct verifications:
verify(mock).someMethod();
verify(mock, times(10)).someMethod();
verify(mock, atLeastOnce()).someMethod();
When i change #InjectMocks to #Mock, The second test it's ok ,but first test it's error.
I need add to a stubbing when(requestListServiceImpl.getAllRequest(anyInt(),anyInt(),anyString(),anyString())).thenReturn(new PageInfo<>());
I don't know how to do it,
Is injectmocks necessary?
Here:
verify(requestListServiceImpl)
And
#InjectMocks
RequestListServiceImpl requestListServiceImpl;
The message is pretty clear: you verify mock objects that Mockito created for you.
#InjectMocks does not create mocks. It rather injects mocks that you have in your test class into a real object.
So, what is necessary here: read the manual or a tutorial. Meaning: don't start with Mockito by applying it immediately to your project. Instead, step back, and look at simple examples to understand how it is supposed to be used.
In your current setup: requestListServiceImpl is a real object. So you should check if that class offers you methods to verify its internal status. You triggered some action on it, but because it is a real object, Mockito doesn't know what you did. But how to actually solve this depends on YOUR code base.
You want to test requestListServiceImpl you should use #InjectMocks so mockito calls the real method on requestListServiceImpl. When you use #Mock, the method will by default not be invoked.
#InjectMocks will be the same as if you create it yourself with new requestListServiceImpl(mock(requestListDao))
When you use verify(mock).someMethod(); you have to pass a mock to that method, not #InjectMocks.
You want to verify if a certain method is called on a mock inside your class under test(requestListServiceImpl).
Instead of #InjectMocks there is also #Spy, which will kinda do both, you can mock methods in requestListServiceImpl but also call the real method.

PowerMock static method mocking isn't taken into account for each #InjectMocks invocation

I want to write some unit tests, that use JUnit 4.12, Mockito 1.9.5 and PowerMock 1.6.1.
The class has some fields annotated with #Mock, as well as some fields annotated with #InjectMocks.
The attribute that is annotated with #InjectMocks reaches at some point a parent constructor which contains some static method invokation, that should be mocked with PowerMock.
The problem is the first test works seamlessly, while the second test does not seem to mock the static methods at all.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ StaticClass.class })
public class TestClass {
#Mock
private SomeClass attribute1;
#InjectMocks
private SomeOtherClass attribute2;
#BeforeClass
public static void setUp() {
PowerMockito.mockStatic(StaticClass.class);
when(StaticClass.staticMethod(any(), any()).thenReturn(new SomeConcreteClass());
}
#Test
public void test1() {
assertEquals(attribute2.method1(), value1);
}
#Test
public void test2() {
assertEquals(attribute2.method2(), value2);
}
}
public class SomeOtherClass {
private SomeClass attribute;
public SomeOtherClass() {
SomeConcreteClass value = StaticClass.staticMethod(argument1, argument2);
value.someOtherMethod();
}
}
As mentioned before, the first test passes and the StaticClass.staticMethod() is mocked as expected by PowerMock.
The second test does not pass and it throws a NullPointerException at line when someOtherMethod is called on value (because value = null, as the StaticClass.staticMethod was not mocked anymore by PowerMock).
As explained in (Mocking behaviour resets after each test with PowerMock) Powermock resets the mocks before each test.
For some reason it works the first time - there exists
an unresolved bug report for that issue (https://github.com/powermock/powermock/issues/398).
Its arguably bad design, but a way to do what you want is the following:
Instead of relying on the annotation set up the mocks manually.
private SomeClass attribute;
private SomeOtherClass testClass;
#Before
public void setUp() {
PowerMockito.mockStatic(StaticClass.class);
Mockito.when(StaticClass.staticMethod(anyString())).thenReturn(new SomeConcreteClass());
attribute = Mockito.mock(SomeClass.class);
testClass = new SomeOtherClass();
// assign mock manually
testClass.attribute = attribute;
}
The prefered way would be to supply the attribute using the constructor of SomeOtherClass, however since you seem to use a empty constructor
you will have to set the value from the outside. If the attribute instance is not accessible you might be forced to use reflections.
The cleaner way would be to refactor the constructor of you SomeOtherClass to not use a static method inside. Instead passing SomeConcreteClass as a parameter to the constructor is the way to go.
Some people even say you should not have any logic inside of a constructor.

In a JUnit test is there a rule to set the subject of the test

I've been writing a lot of JUnit tests lately and see this same boilerplate pattern.
public class MathOpTest {
private MathOp a;
#Before
public void setUp(){
a = new MathOp();
}
...
}
Is there an annotation to set this up for me as I always need to write a setUp method and it usually only has the single class I'm testing.
Something like:
public class MathOpTest {
#TestSubject
private MathOp a;
...
}
You can assign the fields when they are declared:
public class MathOpTest {
private final MathOp mathOp = new MathOp();
...
}
This is simple and straight-forward, so I recommend that you assign fields in your test class at declaration time whenever possible (certainly in the case you gave).
If you want to understand a bit more, read on.
JUnit will create a unique instance of your test class for each test method, so even if your test modifies internal state of MathOp, using fields this way is safe as long as your tests don't modify global state.
For JUnit4-style tests (i.e. tests that do not extend junit.framework.TestCase) JUnit will create the test class just before the test method is run, and make it eligible for garbage collection after the test method completes.
Use #Before methods for more complex initialization.
Usually I use #Before when:
Initialization of the field is complex
Initialization of the field requires calling code that is declared to throw a checked exception
You need to do initialization after a #Rule has been applied (for instance, injecting a mock into a constructor)
Usually you would create the object under test in the test method when the class needs to be constructed different ways for different use cases.
Examples
Here is an example of using #Before and initMocks():
public class MathOpTest {
#Mock private Calculator mockCalculator;
#Mock private Supplier<Double> mockPreviousResultSupplier;
private MathOp mathOp;
#Before
public void createMathOp() {
MockitoAnnotations.initMocks(this);
mathOp = new MathOp(
mockCalculator, mockPreviousResultSupplier);
}
...
}
Here's an example of a #Before method that uses the result of a #Rule:
public class MyWriterTest {
#Rule public final TemporaryFolder folder = new TemporaryFolder();
private File output;
private MyWriter writer;
#Before
public void createMyWriter() {
output = folder.newFile();
writer = new MyWriter(output);
}
...
}
Aside: I personally wouldn't recommend using #InjectMocks to create the class you are testing. It's too much magic for my taste. Having an explicit constructor is cleaner and simpler, and I like my tests to be clear and simple :-)
Nothing like this directly exists in vanilla JUnit to my recollection. Most people elect to either initialize their test subject in a #Before statement, or inside of their tests. In its defense, it makes it clear what is being established before the tests are run, and it always resets the state of your test object.
If you're using Mockito, you actually do have the benefits of declaring a class and annotating it with #InjectMocks to both instantiate the class and inject whatever #Mock classes you had prior.

Mockito mock objects returns null

I try to implement some tests for my JSF application and for the mocks I am using mockito. (I also use spring)
#RunWith(MockitoJUnitRunner.class)
public class GeneralConfigServiceImplTest {
private GeneralConfigService generalConfigService;
#Mock
private GeneralConfigDAO generalConfigDAO;
#Mock
private GeneralConfig gen;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
generalConfigService = new GeneralConfigService();
ReflectionTestUtils.setField(generalConfigService, "generalConfigDAO", generalConfigDAO);
}
#Test
public void testAddGeneralConfigCallDAOSuccess() throws DAOException, EntityNullException, IllegalEntityArgumentException, ParseException, EntityPersistException {
gen = createGeneralConfigs("label", "value");
generalConfigService.setInstance(gen);
generalConfigService.persist();
log.info(generalConfigService.getInstance().toString());
}
}
The test succeeds, but when I want to retrieve the instance with the getInstance method. All Parameters which I have set before (via the constructor before) are null.
I am new to mocked objects, so is this behavior normal, or is there a mistake in my code?
It really depends on GeneralConfigService#getInstance() implementation. Also you can simplify your test code a lot if you use #InjectMocks annotation.
When using MockitoJUnitRunner you don't need to initialize mocks and inject your dependencies manually:
#RunWith(MockitoJUnitRunner.class)
public class GeneralConfigServiceImplTest {
#InjectMocks
private GeneralConfigService generalConfigService;
#Mock
private GeneralConfigDAO generalConfigDAO;
#Test
public void testAddGeneralConfigCallDAOSuccess() {
// generalConfigService is already instantiated and populated with dependencies here
...
}
}
My problem here was the incorrect import for Test anotation:
Was
import org.junit.jupiter.api.Test;
Correct
import org.junit.Test;
Don't forget to use
MockitoAnnotations.initMocks(this);
If you are Mocking object through annotation i.e. #Mock Objectname
All method calls to Mockito mocks return null by default. If you want it to return something else you need to tell it to do so via a when statement.
It seems the you are thinking that the following will work... you call setInstance and then expect getInstance to return the value that was passed to setInstance since this is how the DAO would work. If this is what you are attempting, you shouldn't test setInstance by then calling getInstance since getInstance will return whatever you have configured the mock to return and will have no relation to what was passed to setInstance. Instead, use verify to validate that the appropriate method of the DAO was called from the setInstance method.
For example, if GeneralConfigService.setInstance calls GeneralConfigDAO.setInstance then your test should look like this...
#Test
public void testAddGeneralConfigCallDAOSuccess() throws DAOException, EntityNullException, IllegalEntityArgumentException, ParseException, EntityPersistException {
gen = createGeneralConfigs("label", "value");
generalConfigService.setInstance(gen);
generalConfigService.persist();
verify(genConfigDAO).setInstance(sameInstance(gen));
}
Also, if gen is a mock (via #Mock) why are you assigning it to something else via gen = createGeneralConfigs...
This thread is an old one, but I got the same problem with junit5 (v5.8.2) and mockito (mockito-core:jar:4.5.1) and none of the answers here helped me. After a 1.5 hours search I found this article:
https://mincong.io/2020/04/19/mockito-junit5/
which helped me! I used the first solution, so I added
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>2.28.2</version>
<scope>test</scope>
</dependency>
as new dependency and I annotated my class with the following annotation (and I removed the #RunWith(MockitoJUnitRunner.class) annotation):
#ExtendWith(MockitoExtension.class)
Please find the explanation in the article. I hope this help to others as well!

Categories

Resources