Mockito: How to Mock objects in a Spy - java

The application runs in JEE environment.
I wish inject a Spy into a bean under test.
The Spy object has also some beans inside that should be injected. How can inject mocks of those beans into the Spy?
This is the usecase:
package testinject2;
import javax.inject.Inject;
public class ABean {
#Inject
BBean b;
public void print() {
System.out.println("Hi, I'm ABean");
b.print();
}
}
package testinject2;
import javax.inject.Inject;
public class BBean {
#Inject
CBean c;
public void print() {
System.out.println("Hi, I'm BBean");
c.print();
}
}
package testinject2;
public class CBean {
public void print() {
System.out.println("Hi, I'm CBean");
}
}
package testinject2;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class ABeanTest {
#Spy
CBean c = new CBean();
#Spy
BBean b = new BBean();
#InjectMocks
ABean beanUnderTest;
#Test
public void test() {
beanUnderTest.print();
}
}
I'm expect to obtain
Hi, I'm ABean
Hi, I'm BBean
Hi, I'm CBean
But instead I have a null ponter exception because CBean is not injected into BBean.
Which is the correct way to Inject a Spy object into another Spy ?

You need to define to which object mocks should be injected via #InjectMocks annotation, but it does not work together with #Spy annotation. See mockito issue.
There is the simplest solution to use Mockito.spy instead of #Spy together with #InjectMocks:
#InjectMocks
BBean b = Mockito.spy(new BBean());
Full test code:
#RunWith(MockitoJUnitRunner.class)
public class ConfigTestObject {
#Spy
CBean c = new CBean();
#InjectMocks
BBean b = Mockito.spy(new BBean());
#InjectMocks
ABean beanUnderTest;
#Test
public void test() {
beanUnderTest.print();
//verify that mocks is working
verify(c, atLeast(1)).print();
verify(b, atLeast(1)).print();
}
}

Related

Problem with testing service that utilises data from mongodb repository

I am trying to test a service that has a mongodb repository. I dont know how to write tests that utilise it though and when I try to create entries from the testing class I keep on getting null pointer exception when I call a method from the mongodb repository. My repository class is called
TagPreferencesRepository
and the exception is thrown when I call
tagPreferencesRepository.deleteAllByTag(tag);
I have declared TagPreferencesRepository using #Mock:
#Mock TagPreferencesRepository tagPreferencesRepository;
and the method throwing the exception is called from inside a method in the testing class, that is annotated with #Before
Methods in the testing class annotated with #Before:
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
and:
#Before
public TagPreferences setUp() {
tagPreferencesRepository.deleteAllByTag(tagEnum);
...
}
Your mock is not being correctly initialized.
It could be that you are not injecting the mock to the instance of what you want to test. Do you have a #InjectMock annotation?
Also, make sure that you are using jUnit for your annotations. I once had a similar experience because I was using org.junit.jupiter.api for some of the annotations instead of org.junit.
Example skeleton:
import org.junit.Before;
import org.junit.Test
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class TestSomeService()
{
#InjectMock
SomeService someService;
#Mock
TagPreferencesRepository tagPreferencesRepository;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void SomeTest(){
TagEnum tag = SomeTag;
// if deleteAllByTag is void
doNothing().when(tagPreferencesRepository).deleteAllByTag(tag);
someResult = someService.someMethod(tag);
// assert something
}
}

How to mock returned object from inner method on some other class in java

I read at least 20 posts but still couldn't find the answer. So, posting this question. May be it is answered in some other post, which I couldn't find.
class OuterService {
InnerService innerService;
#Autowired
public void setInnerService(InnerService innerService){
this.innerService = innerService;
}
public void method() {
List<C> listOfC = new ArrayList<C>();
C c = new C();
c.setUserProfiles(someObject);
c = innerService.invokeMethod(String str1,Map map,
String str2, Object obj1, String str3, String str4,
C c, String str5);
c.setCreatedDate(some String value); // Here c comes null while executing jUnits.
listOfC.add(c);
}
}
Here is my Test class:
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import com.pogo.service.DeviceRegistrationService;
#SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT")
#SpringBootTest
#RunWith(MockitoJUnitRunner.class)
class ClassOuterServiceTest {
#InjectMocks
OuterService outerService;
#Mock
InnerService innerService;
#Mock C c;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
outerService.setInnerService(innerService);
}
#Test
public void methodTest() {
when(innerService.invokeMethod(Mockito.anyString(),
Mockito.any(Map.class), Mockito.anyString(),Mockito.anyString(),
Mockito.any(PersonSessionToken.class), Mockito.anyString(),Mockito.anyString(), Mockito.anyString(),
Mockito.any(RequestHeader.class),Mockito.any(C.class),
Mockito.anyString() )).thenReturn(c);
doNothing().when(c).invokeCMethod();
outerService.method();
}
}
But I get null inside object c in OuterService.java. Also if I use Matchers.any() or Matchers.anyString() in invokeMethod() then , it shows Matchers exception.
What is the appropriate solution?
You don't need to create the object for OuterService use #InjectMocks annotation and when you use method stubbing use mock objects only. In your program you are creating object for c. Instead of creating object just use #Mock annotation.
When you using Mockito.any() mention the class inside parenthesis. Mockito.any(C.class) like this.
Don't use PowerMockRunner unless you are testing static or final classes.
#SpringBootTest
#RunWith(MockitoJUnitRunner.class)
public class ClassOuterServiceTestC {
#Mock
public InnerService innerService;
#InjectMocks
public OuterService outerService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void methodTest() {
C obj = mock(C.class);
when(innerService.invokeMethod(anyString(), anyMap(), anyString(), any(), anyString(), anyString(), any(TestC.class), anyString()))
.thenReturn(obj);
doNothing().when(obj).setUserProfiles(any(Object.class));
doNothing().when(obj).setCreatedDate(anyString());
outerService.method();
}
}

Create #MockBean with qualifier by annotating class?

In my Spring Boot test I'm using 2 mock beans with different qualifiers:
#RunWith(SpringRunner.class)
#SpringBootTest
class HohoTest {
#MockBean #Qualifier("haha") IHaha ahaha;
#MockBean #Qualifier("hoho") IHaha ohoho;
}
Since I'm not using these beans explicitly, I would rather move them away from the class body, as the #MockBean annotation is now repeatable:
#RunWith(SpringRunner.class)
#SpringBootTest
#MockBean(IHaha.class)
#MockBean(IHaha.class)
class HohoTest {}
However, I need to pass in a qualifier as well, since they have the same type. Any idea on how I can achieve that?
Because using annotation #Qualifier means choose bean by name, so you can set up a name for a mock with code like this:
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {JsonMapperConfig.class})
public class IntegrationFlowTest {
#MockBean(name = "s3MessageRepository")
private S3Repository s3MessageRepository;
// etc
If it is okay to move the mock definition completely out of the test class, you could also create the mocks in a separate #Configuration class:
#Configuration
public class MockConfiguration
{
#Bean #Qualifier("haha")
public IHaha ahaha() {
return Mockito.mock(IHaha.class);
}
#Bean #Qualifier("hoho")
public IHaha ohoho() {
return Mockito.mock(IHaha.class);
}
}
When declaring #MockBean at the class level, there is currently no support for providing a qualifier.
If you would like to have such support, I suggest you request it in the Spring Boot issue tracker.
Otherwise, you will need to continue declaring #MockBean on fields alongside #Qualifier.
I had a similar requirement of injecting mocked service beans with #Order annotation. I also needed to verify the invocation count of service functions. Below is my implementation. It might help someone.
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest
public class ServiceNameTest {
#Autowired private ServiceName serviceName;
// Important: Used to reset interaction count of our static
// bean objects before every test.
#Before
public void reset_mockito_interactions() {
Mockito.clearInvocations(MockServicesConfig.bean1);
Mockito.clearInvocations(MockServicesConfig.bean2);
}
#Configuration
public static class MockServicesConfig {
public static InterfaceName bean1;
public static InterfaceName bean2;
#Bean
#Order(1)
public InterfaceName bean1() {
bean1 = Mockito.mock(InterfaceName.class);
// Common when() stubbing
return bean1;
}
#Bean
#Order(2)
public InterfaceName vmpAdapter() {
bean2 = Mockito.mock(InterfaceName.class);
// Common when() stubbing
return bean2;
}
}
#Test
public void test_functionName_mock_invocation1() {
// Arrange --> Act --> Assert
// nullify other functions custom when() stub.
// updating this functions custom when() stub.
verify(MockServicesConfig.bean1, times(1)).functionName("");
}
#Test
public void test_functionName_mock_invocation2() {
// Arrange --> Act --> Assert
// nullify other functions custom when() stub.
// updating this functions custom when() stub.
verify(MockServicesConfig.bean1, times(1)).functionName("");
}
}
This should now work
#SpringBootTest(
classes = Some.class
)
#MockBean(name = BEAN_NAME, classes = TheBeanClass.class)
#MockBean(name = BEAN_NAME_2, classes = TheBeanClass.class)
class SomeTest {
private final Some some;
#Autowired
SomeTest(Some some) {
this.some = some;
}
}
Please note, if you need to use any of the mocked beans, you will have to put the #Qualifier in the constructor, for example
private final TheBeanClass theBeanclass;
private final Some some;
#Autowired
SomeTest(Some some, #Qualifier(BEAN_NAME) TheBeanClass theBeanClass) {
this.some = some;
this.theBeanClass = theBeanClass;
}

How to get away with NPE for #Inject field while unit testing?

Im writing unit tests for the below code, Im getting NPE even though Im mocking the fields, How can I resolve that. Those fields are present with #Inject annotation
#Component
interface A {
void run();
}
class B {
#Inject
A a;
void someMethod() {
a.run();
}}
class C{
#Inject
B b;
void anotherMethod() {
b.someMethod();
}
}
class CTest {
#Mock
B b;
// remains null when invoked in the actual class though its mocked instance is
// present here
#Mock
A a;
//// remains null when invoked in the actual class though its mocked instance
//// is present here
#InjectMocks
C c;
#Before
public void initialize() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
c.anotherMethod();
}
}
So how can I get the mocked value in the actual class where the field is injected with #Inject using Mockito?
My guess is that you should annotate your CTest class with #RunWith(MockitoJUnitRunner.class) and remove your before-method as it will become unecessary (#RunWith will do the trick of injecting mocks).
UPDATE
Actually I ran your code in my IDE. And everything is just fine, no NPE. Probably you have to check that your imports are correct. Here are mine to compare with yours:
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import javax.inject.Inject;
import org.springframework.stereotype.Component;
Also, please, pay attention that you declared Class C with upper case letter (should be class C) in your question, thus this very code won't compile.

Spring test service class mocking utility class- Junit and Mockito

I want to write test cases for service layer of spring framework using Junit + Mockito.
How to call the actual service layer method using my ServiceTest class, If i mock the ServiceTest class then it's object wont execute the actual service method code because it wont get the object to call it's methods and if I try with the Spy still it was not working, I tried this example
still I not able to execute the test cases.
MyService.java
#Service
public class MyService{
#Autowired
Utility utility;
public String showResult(){
String result = utility.getName();
return result;
}
}
MyServiceTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=AnnotationConfigWebContextLoader.class)
#WebAppConfiguration
public class MyServiceTest {
#Autowired
MyService myService;
#Autowired
Utility utility;
#Test
public void testShowResult() throws Exception {
assertEquals("Test",myService.showResult());
}
#Configuration
static class MykServiceTestContextConfiguration {
#Bean
public MyService myService() {
return new MyService();
}
#Bean
public Utility utility() {
return Mockito.mock(Utility.class);
}
}
}
You have to first mock the Utility class and then have to invoke it before calling your #Test using MockitoAnnotations.initMocks(this) as follows:
MyServiceTest.java
import static org.mockito.Mockito.when;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.AnnotationConfigWebContextLoader;
import org.springframework.test.context.web.WebAppConfiguration;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigWebContextLoader.class)
#WebAppConfiguration
public class MyServiceTest {
#InjectMocks
private MyService myService;
#Mock
private Utility utility;
#Before
public void setupMock() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testShowResult() throws Exception {
when(utility.getName()).thenReturn("Test");
Assert.assertEquals("Test", myService.showResult());
}
#Configuration
static class MykServiceTestContextConfiguration {
#Bean
public MyService myService() {
return new MyService();
}
#Bean
public Utility utility() {
return new Utility();
}
}
}
MyService.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class MyService {
#Autowired
private Utility utility;
public String showResult() {
String result = utility.getName();
return result;
}
}
Utility.java
import org.springframework.stereotype.Component;
#Component
public class Utility {
public String getName() {
return "hello";
}
}
Make use of #Spy
When spy is called, then actual method of real object is called.
https://www.tutorialspoint.com/mockito/mockito_spying.htm
please go through the tutorial
This worked for me
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#WebAppConfiguration
public class MyServiceTest {
#Spy
MyService myService;
#Test
public void testShowResult() throws Exception {
assertEquals("Test",myService.showResult());
}
#Service
public class MyService{
public String showResult(){
return "Test";
}
}
}
still having issues share the spring version you are using
How about using #MockBean? It suits Spring + JUnit and, probably you need to implement mock behavior.
I guess that Utility.getName() return "Test" in the test case.
The following is the test code I tried.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigWebContextLoader.class)
#WebAppConfiguration
public class MyServiceTest {
#Autowired
MyService myService;
#MockBean
Utility utility;
#Test
public void testShowResult() throws Exception {
Mockito.when(utility.getName()).thenReturn("Test");
assertEquals("Test", myService.showResult());
}
#Configuration
static class MykServiceTestContextConfiguration {
#Bean
public MyService myService() {
return new MyService();
}
}
}

Categories

Resources