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;
Related
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));
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 have a special case, where I have to mock some fields and use both #Mock and #Spy for my class, which is under test, because at some tests I need to change behaviour of it's own methods. I use #InjectMocks for constructor. It looks like this:
Test class:
#RunWith(MockitoJUnitRunner.class)
public class ServiceTest {
#Mock
private SomeObject usedAsNonFinal;
#Mock
private SomeObject usedAsFinal;
#Spy
#InjectMocks
private ServiceTest service = new ServiceTest(usedAsNonFinal, usedAsFinal);
#Before
public void setup() {
when(usedAsNonFinal.someMethod(Matchers.any()))
.thenReturn(someObject);
when(usedAsFinal.someMethod(Matchers.any()))
.thenReturn(someObject);
doReturn(someObject).when(service).someMethod(Matchers.any());
}
}
Service, which is under test:
#Service
public class Service {
private SomeObject usedAsNonFinal //injects correctly
private final SomeObject usedAsFinal; //null - not injected
#Autowired
public Service (SomeObject usedAsNonFinal, SomeObject usedAsFinal){
this.usedAsNonFinal = usedAsNonFinal;
this.usedAsFinal = usedAsFinal;
}
//some methods to mock depending on test
}
The problem is - as commented in code - that final field is not getting injected and it's null. When I remove final keyword it gets injected correctly and all tests are working as expected. I tried some tricks from other topics - also using reflection, but nothing seems to be workking in this particular case.
Did you try don't instantiate ServiceTest in test?
#InjectMocks should do it for you. Try just
#Spy
#InjectMocks
private ServiceTest service;
How I can mock A with B mock as constructor parameter?
private B actionContext;
private A target;
#BeforeEach
void setUp() {
actionContext = mock(B.class);
target = mock?
}
public class A {//...
public A(B b){//...
}
}
You can use the mockito annotation
#Mock
private B mockB;
#Spy
#InjectMocks
private A testObj = new A(mockB);
set up test behavior in setUp method...
when(mockB.method()).thenReturn();
if you want to mock class A methods you don't need to mock class B
mocking class A is enough
#BeforeEach
void setUp() {
A mockedA = mock(A.class);
}
And if you want to use mocked methods of class B you can mock it separately
#BeforeEach
void setUp() {
A mockedA = mock(A.class);
B mockedB = mock(B.class);
}
also will suggest you to read Mockito docs to understand mocking principles .
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.