Mocking in Tests with #MockBean or #Autowired - java

I have this Junit test, where I have an object that I want to mock the BackendHotelService object; I used #MockBean and #Autowired, but in both I got a java.lang.NullPointerException when running the test
#Component
public class FindHotelDataRequestTransformer extends HotelDataRequestTransformer {
public FindHotelDataRequestTransformer(BackendHotelService backendHotelService) {
super (backendHotelService);
}
..
}
and the test:
public class FindHotelDataRequestTransformerTest {
#MockBean
//#Autowired
private BackendHotelService backendHotelService;
private FindHotelDataRequestTransformer transformer;
#Before
public void setUp() {
transformer = new FindHotelDataRequestTransformer( backendHotelService);
}
the backendHotelService is never used

When creating a new FindHotelDataRequestTransformer, do you access any fields of backendHotelService?
if so you will need to mock the response.
Try below
Mockito.when(backendHotelService.name()).thenReturn("test);

Related

Why tested class based autowire annotation throw null exception?

I use Spring Boot 5 and JUnit in my project. I create a unit test to test the service.
Here is the service that I am testing:
#Service
#RequiredArgsConstructor
#Slf4j
public class BuilderServiceImpl implements BuilderService{
#Autowired
public AutoMapper autoMapper;
private final BuilderRepository builderRepository;
private final AdminUserRepository adminUserRepository;
#Override
public BuilderDto getByEmail(String email){
}
#Override
public List<BuilderMinDto> getAll() {}
#Override
public List<BuilderMinDto> getAll(int page, int size) {}
#Override
public SaveBuilderResponse create(Builder builder){
var str = autoMapper.getDummyText();
Builder savedBuilder = builderRepository.save(builder);
return new SaveBuilderResponse(savedBuilder);
}
}
And here is the test class that tests the service above:
#SpringBootTest
#RequiredArgsConstructor
#Slf4j
class BuilderServiceImplTest {
#Mock
private BuilderRepository builderRepository;
#Mock
private AdminUserRepository adminUserRepository;
private AutoCloseable autoCloseable;
private BuilderService underTest;
#BeforeEach
void setUp(){
autoCloseable = MockitoAnnotations.openMocks(this);
underTest = new BuilderServiceImpl(builderRepository,adminUserRepository);
}
#AfterEach
void tearDown () throws Exception{
autoCloseable.close();
}
#Test
void getByEmail(){}
#Test
#Disabled
void getAll() { }
#Test
#Disabled
void testGetAll() {}
#Test
void create() {
//given
Builder builder = new Builder();
builder.setName("John Johnson");
builder.setCompanyName("Builders Test");
builder.setEmail("test#builders.com");
//when
underTest.create(builder);
//then
ArgumentCaptor<Builder> builderArgumentCaptor = ArgumentCaptor.forClass(Builder.class);
verify(builderRepository)
.save(builderArgumentCaptor.capture());
Builder captureBuilder = builderArgumentCaptor.getValue();
assertThat(captureBuilder).isEqualTo(builder);
}
}
When I start to run the test class the create method in BuilderServiceImpl fired and on this row:
var str = autoMapper.getDummyText();
I get NullPointerException(autoMapper instance is null).
Here is the definition of AutoMapper class:
#Component
#Slf4j
#RequiredArgsConstructor
public class AutoMapper {
public String getDummyText(){
return "Hello From AutoMapper.";
}
}
As you can see I use #Component annotation to register the AutoMapper class to the IoC container and Autowired annotation to inject it into autoMapper property in BuilderServiceImpl class.
Why autoMapper instance is null? How can I make autoMapper to be initialized?
In order to make #Autowire work you have to use the instance of BuilderServiceImpl (object under test) created by spring itself.
When you create the object like this (by yourself, manually):
#BeforeEach
void setUp(){
....
underTest = new BuilderServiceImpl(builderRepository,adminUserRepository);
}
Spring doesn't know anything about this object, hence Autowiring won't work
Another thing that might be useful:
You've used #Mock for BuilderRepository and AdminUserRepository.
This are plain mockito annotation, and if you're using an integration/system test that runs the spring under the hood, probably this is not what you want:
Surely, it will create a mock, but it won't put it onto an application context, and won't substitute the beans of these classes that might have been created by spring.
So if this is what you want to achieve, you should use #MockBean instead.
This annotation belongs to Spring Testing framework rather than a plain mockito annotation.
All-in-all you might end up with something like this:
#SpringBootTest
class MyTest
{
#MockBean
BuilderRepository builderRepo;
#MockBean
AdminUserRepository adminUserRepo;
#Autowired // spring will inject your mock repository implementations
// automatically
BuilderServiceImpl underTest;
#Test
void mytest() {
...
}
}
Add #Autowire annotation Annotations on below fields. Error due your not initialized below object In BuilderServiceImpl
#Autowire
private final BuilderRepository builderRepository;
#Autowire
private final AdminUserRepository adminUserRepository;
Why are you creating BuildService manually? If you do this, set AutoMapper manualy too.
#BeforeEach
void setUp(){
autoCloseable = MockitoAnnotations.openMocks(this);
underTest = new BuilderServiceImpl(builderRepository,adminUserRepository);
underTest.setAutoMapper(new AutoMapper());
}
You are not using di.

how to mock private variable in RestController class

I am doing some web unit testing with Spring. is there a way I can mock the instance of MyProcessor which get set in #PostConstruct? I tried with #MockBean but it gets set as null and getting null pointer exception?
I am using a factory to instantiate MyProcessor based on some boolean flag. But if there is a different approach altogether that would make my test cleaner, I am open to ideas.
Please Note I am using Junit 5.
public class Controller {
private final AProcessorFactory factory;
#Value("${tt.f.processor.async}")
private boolean isAsync;
private MyProcessor myProcessor;
public Controller(final AProcessorFactory factory) {
this.factory= factory;
}
#PostConstruct
public void init() {
myProcessor = factory.getInstance(isAsync);
}
}
#WebMvcTest(Controller.class)
public class ControllerTest{
#MockBean
private MyProcessor processor;
#MockBean
private AProcessorFactory factory;
#Autowired
private MockMvc mockMvc;
#Test
public void test() throws Exception {
when(processor.process(any(Request.class), any(String.class)))
.thenReturn(new TestResponse("123", SUCCESS, "", ""));
}
It looks like your myProcessor is actually built by your AProcessorFactory in a PostConstruct init() method.
You'll want to provide a behavior for your AProcessorFactory mock.
First, you would probably want to set up your myProcessor in your constructor as the #PostConstruct init() method has no special context loading logic with it.
public class Controller {
#Value("${tt.f.processor.async}")
private boolean isAsync;
private MyProcessor myProcessor;
public Controller(final AProcessorFactory factory) {
this.myProcessor = factory.getInstance(isAsync);
}
}
You can specify this in a #Before step in your test.
#MockBean
private AProcessorFactory factory;
#Before
public void setUp() {
when(processor.process(any(Request.class), any(String.class)))
.thenReturn(new TestResponse("123", SUCCESS, "", ""));
when(factory.getInstance(any())).thenReturn(processor)
}
Spring will register your AProcessorFactory mock that has been loaded with the appropriate behaviors.

Unable to wire in dependency using MockBean in WebMVCTest

I have a controller class:
public class Controller {
private final IProcessor processor;
public Controller (final ProcessorFactory factory) {
this.processor = factory.getInstance();
}
}
A Factory class to provide the different instances of IProcessor:
#Component
public class ProcessorFactory {
private final Dep1 dep1;
private final Dep2 dep2;
public ProcessorFactory (final Dep1 dep1,
final Dep2 dep2) {
this.dep1= dep1;
this.dep2= dep2;
}
public IProcessor getInstance() {
if (...) {
return new ProcessorA(dep1, dep2);
}
return new ProcessorB(dep1, dep2);
}
}
In my mockito test class where I use Junit5, I am not able to instantiate the IProcessor member and is null:
#WebMvcTest(Controller.class)
public class ControllerTest {
#MockBean
private ProcessorFactory processorFactory ;
#MockBean
private IProcessor processor;
#Autowired
private MockMvc mockMvc;
#Test
public void test1() throws Exception {
when(processor.process(any(Request.class), any(String.class)))
.thenReturn(new BlaBla("Test", "Test"));
String request = ...
this.mockMvc.perform(post("/test/test").contentType(MediaType.APPLICATION_JSON).content(request))
.andDo(print())
.andExpect(status().is2xxSuccessful());
}
}
I am not sure I am using MockBean correctly. Basically I want to mock both the Factory and the Processor.
Since you need to call a mocked method (getInstance()) during Spring context initialization (inside the Controller's constructor), you need to mock the said method in a different way. The mocked bean has to be not only provided as an existing object, but also it should have it's mocked behavior defined.
Addtionally, IProcessor implementations are not configured as Spring beans, so Spring will not inject them - ProcessorFactory calls new explicitly and creates the objects without Spring involvement.
I've created a simple project to reproduce your problem and provide a solution - you can find it here on GitHub if you want to check if the whole thing is working, but here's the most important test snippet (I've simplified the methods a bit):
#WebMvcTest(Controller.class)
class ControllerTest {
private static final IProcessor PROCESSOR = mock(IProcessor.class);
#TestConfiguration
static class InnerConfiguration {
#Bean
ProcessorFactory processorFactory() {
ProcessorFactory processorFactory = mock(ProcessorFactory.class);
when(processorFactory.getInstance())
.thenReturn(PROCESSOR);
return processorFactory;
}
}
#Autowired
private MockMvc mockMvc;
#Test
void test1() throws Exception {
String result = "this is a test";
when(PROCESSOR.process(any()))
.thenReturn(result);
mockMvc.perform(post("/test/test")
.contentType(MediaType.APPLICATION_JSON)
.content("{}"))
.andDo(print())
.andExpect(status().is2xxSuccessful())
.andExpect(content().string(result));
}
}

Mockito - Creating nested mock objects

I'm learning Mockito. I am facing problem while creating mock for nested objects. See
public interface BaseManager {
public Query createQuery(String queryString);
}
and an implementation class for that
public class BaseManagerImpl implements BaseManager {
#Autowired
private SessionFactory sessionFactory;
// ...
}
Module level hibernate manager, for example:
public interface RegistrationManager {
#Transactional
public List<Country> getCountries();
}
and an implementation class for that
public class RegistrationManagerImpl implements RegistrationManager {
#Autowired
private BaseManager baseManager;
// ...
}
Now I'm facing problem in creating mocked base manager. My test class is:
public class MockitoTest {
private RegistrationManager registrationManager = new RegistrationManagerImpl();
#Mock private BaseManager baseManager;
#Mock private SessionFactory sessionFactory;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
// baseManager.setSessionFactory(sessionFactory);
registrationManager.setBaseManager(baseManager);
}
// ...
// #Test
}
Problem: sessionFactory is not instantiated inside baseManager.
Please help creating mock object. Thanks in advance!
The problem is that you are creating a mock of BaseManager but only BaseManagerImpl has a SessionFactory field. Mockito doesn't know about BaseManagerImpl. In your code you create two mocks which are completely independent of each other.
Unit tests are about testing an unit. So you should test BaseManagerImpl and RegistrationManagerImpl separately.
So you test BaseManagerImpl first:
public class BaseManagerImplTest {
private BaseManagerImpl target;
// ...
}
then you test RegistrationManagerImpl:
public class RegistrationManagerImplTest {
private RegistrationManagerImpl target;
// ...
}
I suggest that you should use the name target or something similar for your test target in your test class becaues it will make your code much more easier to read.
Another thing: If you test an object all of its dependencies should be mocked but you shouldn't care about the mocks' dependencies. You just mock their method invocations like:
Mockito.when(myMock.someMethod()).thenReturn(someResultObject);
You have to put the #InjectMocks annotation before class you want to test and mock the methods which are called by the basemanger or sessionFactory.
public class MockitoTest {
#InjectMocks
private RegistrationManager registrationManager = new RegistrationManagerImpl();
#Mock private BaseManager baseManager;
#Mock private SessionFactory sessionFactory;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
// baseManager.setSessionFactory(sessionFactory);
registrationManager.setBaseManager(baseManager);
Mockito.when(baseManager.yourMethod()).thenReturn(someObject);
}
// ...
// #Test
}
Hope this is it you're looking for!
You cannot inject a mock of SessionFactory into a mock of BaseManager.
As you are testing RegistrationManagerImpl, you just need to have a mock of BaseManager. You can use method stubbing so that the methods BaseManager will return the stubbed values when those methods are called from RegistrationManagerImpl methods. So, if you have a RegistrationManagerImpl as this:
public class RegistrationManagerImpl implements RegistrationManager {
#Autowired
private BaseManager baseManager;
// ...
public String doSomething(){
return baseManager.process();
}
}
you can write your MockitoTest as this:
public class MockitoTest {
#InjectMocks
private RegistrationManager registrationManager = new RegistrationManagerImpl();
#Mock private BaseManager baseManager;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
// ...
#Test
public void test() {
when(baseManager.process()).thenReturn("hello");
assertEquals("hello", registrationManager.doSomething());
}
}
And while testing BaseManager, there you need to use mock of SeesionFactory.

autowired dependency not getting mocked while executing test case with junit and mockito

I am using Junit4 and Mockito for test cases, in the following code dbprop.getProperty("config") is throwing a NullPointerException because dbProp is null. Please help me out why it was not mocked?
public abstract class BaseClass {
#Autowired
protected DBproperties dbprop;
}
public class SampleClass extends BaseClass {
#Autowired
private OrderService orderService;
valdiateOrder(String input) {
String config = dbprop.getProperty("config");
}
}
public class TestSampleClass {
#InjectMocks
SampleClass sampleClass;
#Mock
private OrderService orderService;
#Test
public void testValidateOrder() {
DBproperties dbprop = mock(DBproperties .class);
when(dbprop.getProperty("config")).thenReturn("xxxx");
assertNotNull(SampleClass.valdiateOrder("xxx"));
}
}
Your dbprop mock has not been injected into sampleClass, you need to add:
#Mock
private DBproperties dbprop;
Then remove the dbprop mock creation from your test method:
#Test
public void testValidateOrder() {
// DBproperties dbprop = mock(DBproperties .class); <-- removed
when(dbprop.getProperty("config")).thenReturn("xxxx");
assertNotNull(SampleClass.valdiateOrder("xxx"));
}
Next, to ensure mocks are injected when using the #InjectMocks annotations you need to either add the following runner:
#RunWith(MockitoJUnitRunner.class)
public class TestSampleClass {
...
Or call the following in a #Before method:
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
See the MockitoAnnotations and MockitoJUnitRunner JavaDocs for more information on the two approaches.
You can annotate your Object with #Mock, so its look like this
#Mock
DBproperties dbProperties;#Before public void init(){ MockitoAnnotations.initMocks(this);
}

Categories