Am using Mockito version 3.6.28 for Junit testing. Am getting Nullpointer Exception while calling the real method on the object. Its because of the dependency on the target object is not injected correctly .This is the code am using.
public class ClassA{
#Autowired
LoggingService loggingService;
#Autowired
ClassB classB;
publc void doSomething(){
loggingService.info("info log"); // This will works fine
classB.doSomething();
}
}
public class ClassB{
#Autowired
LoggingService loggingService;
public void doSomething(){
loggingService.info("info log"); // Nullpointer on this line since loggingService is null
}
}
#RunWith(MockitoJUnitRunner.Silent.class)
public class TestClass{
#InjectMocks
ClassA classA;
#Mock
ClassB classB;
#Mock
private LoggingService loggingService;
#Test
public void testMethod(){
doCallRealMethod().when(classB).doSomething();
classA.doSomething();
}
}
Nullpointer Exceptions in Mockito are usually caused by missing dependencies as you said.
In your case ClassA's are injected accordingly, but when it comes to ClassB it is a Mock object ( i.e no dependencies are injected).
So you would have to inject the Mock's of ClassB while using ClassB.
Something like
#Test
public void testMethod(){
#InjectMocks
ClassB classB_1;
doCallRealMethod().when(classB_1).doSomething();
classA.doSomething();
}
The problem is that You are Injecting mocks only into ClassA and not into ClassB:
#InjectMocks
ClassA classA;
#Mock
private LoggingService loggingService;
#Mock
private ClassB classB;
So, the loggingService inside ClassB is null (it was not injected), and so it is throwing NullPointerException.
The thing is, if You are testing ClassA - most probably You should not call the real method of ClassB, You should mock it.
However if you have to do it, there is a way.
InelliJ is suggesting that instead of #Autowire it is better to use constructors (it is easy to do with lombok). When you have dependencies injected with constructor, it would be then much easier to pass a mock like:
private ClassB classB = new ClassB (mock(LoggingService.class));
Related
I have a class A which has a methodA calling a methodB in class B.
In class B methodB is calling methodC in class C.
Class C implements methodC.
I am trying to test methodA in class A using junit, mockito.
#ExtendWith(MockitoExtension.class)
public class ClassATest {
#Mock
APIGatewayProxyRequestEvent event;
#Mock
Context context;
#Spy
#InjectMocks
ClassB classB;
#Spy
#InjectMocks
ClassA classA;
#Test
#DisplayName("everything should pass")
public void testMethodA() throws Exception {
Person p = new Person("xyz", "abc", 12345, true);
when(classB.methodB(any(Molecule.class), eq("abc"), eq(12345), eq(null))).thenReturn(p);
Map<String, String> headerMap = new HashMap<>();
headerMap.put("id", "12345");
when(event.getHeaders()).thenReturn(headerMap);
when(event.getBody()).thenReturn("{name:hello}");
assertEquals(classA.methodA(event, context).getStatusCode(), 500);
}
I am getting an error of null pointer exception for class C methodC. Do I need to mock that as well? Is there a way I can mock methodB so that the test does reply on the implementation in methodB? As my aim is to test methodA, I am fine mocking other methods.
You are not mocking ClassB, you are using the real implementation:
#Spy
#InjectMocks
ClassB classB;
If you want to mock it, you need to remove those two annotations and have #Mock instead:
#Mock
ClassB classB;
I have a class A, it has a dependency on a repository (maybe JPA repository).
Class A{
#Autowired
SomeRepository somerepository;
public int methodA() {
somerepository.findAll();
methodB();
}
public methodB() {
//do something
}
}
Now I want to write a test code that will mock the public methodB() and return some default value when its called. This can be done by mocking the ClassA bean.
Also I want to mock the repository so that when the repository findAll() method is called then some default value is returned ie mock repository and inject it into the ClassA bean.
Is there any way to fulfill both conditions?
Thanks in Advance !!
You can use spy type for this.
A a = Mockito.spy(new A());
you can mock the method below:
when(a.methodB()).thenReturn(XXX);
or
doNothing().when(a).methodB();
You can use #Spy for partial mocking(method B) and #InjectMocks to inject your mocked repository into your Class, something like this will work:
RunWith(MockitoJUnitRunner.class)
public class SpringDemoTest
{
#InjectMocks
#Spy
ClassA classA;
#Mock
SomeRepository someRepository;
#Test
public void testMethodA()
{
MockitoAnnotations.initMocks(this.getClass());
Mockito.when(classA.methodB()).thenReturn(50);
Mockito.when(someRepository.findAll()).thenReturn("This is a Mock!");
Assert.assertEquals("This is a Mock!", classA.methodA());
}
}
I am having one #Inject object which i need to mock its throwing NPE while using #InjectMocks at my test class
Below is the structure of my class
Class ChildClass extends ParentClass
{
public myMethod(){
String myval=callParentClassMethod();
}
Class ParentClass{
#Inject
private MyService myservice;
//there is no constructor or setter method for this injected object
protected String callParentClassMethod(){
retrun myservice.getStringval();
}
}
Can you please suggest how to mock this MyService object.I have used #Mock and #Injected mock but its not working getting NPE. i tried to inject in both Base class and parent class but no luck.
following works for me:
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#InjectMocks
private ChildClass childClass = new ChildClass();
#Mock
private MyService service;
#Test
public void test1() {
childClass.myMethod();
}
}
UPDATE
I've uploaded example project with test to https://github.com/shurick-k/mock-test
You've not specified exactly what type of #Inject annotation is used, so I assumed it is from javaee-api. Actually it does not matter.
I'm trying to write a test case for a java class. I've mocked a method using Mockito, but the mock is never being used. Why?
Below is the structure of my java class:
class A {
#Autowired
private ClassB classB;
publiv void methodOne() {
methodTwo();
}
private void methodTwo() {
...
int returnedValue = classB.someMethod();
...
}
}
The test class is given below:
class ATest {
#Mock
private ClassB classB;
#InjectMocks
#Autowired
ClassA classA;
#Before
public void setupTest() {
MockitoAnnotations.initMocks(this);
}
#Test(expected = SomeException.class)
public void testMethodOne() {
when(classB.someMethod()).thenReturn(29);
classA.methodOne();
}
}
The test class is extended from another which has the #RunWith(SpringJUnit4ClassRunner.class) annotation.
I've gone through the existing questions but have been unable to find an answer. If there is any question/answer that may help me, please point me to the same.
Thanks in advance!
You could try to remove #Autowired in your test class ATest.
#InjectMocks should be sufficient as it creates your test object and injects your mock.
Depending on your JUnit runner #Autowired might perform a second injection after #InjectMocks which overrides your mocked method setup.
First, a few notes on your test:
- the test should be public
- class A should be public
- there is no need for #Autowire in the test
- there is no need to call initMocks
Then, your test isn't actually testing if the mock is being used or not. Let's change these method so that they now return the value, so that we can test if they work or not:
public class ClassA {
#Autowired
private ClassB classB;
public int methodOne() {
return methodTwo();
}
private int methodTwo() {
return classB.someMethod();
}
}
public class ClassB {
public int someMethod() {
return 0;
}
}
We can now test:
#RunWith(MockitoJUnitRunner.class)
public class ATest {
#Mock
private ClassB classB;
#InjectMocks
ClassA classA;
#Test
public void testMethodOne() {
when(classB.someMethod()).thenReturn(29);
final int result = classA.methodOne();
assertEquals(29, result);
}
}
And the test passes - meaning the mock is being used correctly.
Hope that helps.
What you're missing is that annotations are just declarations. The #Mock and #InjectMocks annotations don't do anything. They are only markers that can be seen by the test runner to perform specific runner-specific behavior. You need a #RunWith annotation to specify a test runner, but you need a specific test runner for specific behavior. If you're using the SpringJUnit4ClassRunner, then none of the Mockito annotations will be used. In any case, I wouldn't want to use the SpringJUnit4ClassRunner for unit tests, as you should just be verifying business logic, not wiring.
Change your test class to use #RunWith(MockitoJUnitRunner.class) and remove the base class reference.
If I create a mock in my spring context file using Springockito as described here, how do I mock some behavior for it?
What I'm trying to do:
ClassA is being tested.
ClassB is autowired in ClassA.
ClassB is being mocked with Springockito.
ClassA needs ClassB to do something in its PostConstruct.
I need to mock ClassB to do that something, since it can't and shouldn't really do it.
Doing this is straight forward without using Springockito (using Mockito straight up), but I need to autowire these beans and use Spring in my tests. Any help is appreciated.
Note that new springockito-annotations help to achieve the same goal without messing with xml context and extra helper classes:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = SpringockitoContextLoader.class, locations = "classpath:test-config.xml")
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class MemoAutoTest extends AbstractJUnit4SpringContextTests {
#Autowired
private ClassA classA;
#Autowired #ReplaceWithMock
private ClassB classB;
#Test
public void testClassA() {
// stub B
when(classB.foo()).thenReturn(true);
when(classB.bar()).thenReturn(42);
// test A
}
}
This would cause ClassB to be replaced with mock at main application context initialization.
I'm not familiar with Springockito, but it looks interesting for some narrow cases - namely integration testing with mocking just a bit.
Anyway, it looks like for a straightforward use case you extend AbstractJUnit4SpringContextTests, you could also autowire ClassB in your test just like you do in ClassA. Then you could define your expected behavior for ClassB in your setup method.
But I think that you need to set up some behavior for the ClassB bean before you get access to it in your setup method. In that case, you may need another bean to set up ClassB to do the expected behavior. So your testContext.xml would have something like this in it:
<bean id="classA" class="com.jarvis.ClassA" depends-on="classBMockSetter" />
<mockito:mock id="classB" class="com.jarvis.ClassB" />
<bean id="classBMockSetter" class="com.jarvis.test.ClassBMockSetter">
<property name="classB" ref="classB" />
</bean>
The ClassBMockSetter would look something like:
public class ClassBMockSetter {
private ClassB classB;
public void setClassB(ClassB classB) {
this.classB = classB;
given(classB.foo()).willReturn(true);
given(classB.bar()).willReturn(42);
}
}
I think that would work, but at that point, isn't it easier to just hand-code your mock ClassB?
What is worked for me is using #InjectMocks notation.
(See https://bitbucket.org/kubek2k/springockito/wiki/Home)
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = SpringockitoContextLoader.class, locations = "classpath:test-config.xml")
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class MemoAutoTest extends AbstractJUnit4SpringContextTests {
#Autowired
private ClassA classA;
#Autowired #InjectMocks
private ClassB classB;
#Test
public void testClassA() {
// stub B
when(classB.foo()).thenReturn(true);
when(classB.bar()).thenReturn(42);
// test A
classA.doSomethingThatInternallyCallClassBFoo();
}
}