Junit test fails when autowired is used - spring

I am trying to run JUnit test for my controller which has 2 autowired fields .
While running it, I am getting a null pointer exception on this object, hence failing to execute. I am new to this Spring JUnit test.
I tried almost all combination that was posted earlier related to JUNIT. None of them works.
helper and model are two autowired fields used in my test. My test goes to the controller and fails with null pointer exception. The object helper exist in my Test class, but it is null in the controller.
Can anyone help me in finding a solution this. Below is my code
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "xml/applicationContext.xml"})
#WebAppConfiguration
public class XYZTest {
WebApplicationContext webApplicationContext;
#Autowired
#Qualifier("helper")
Helper helper;
#Autowired
#Qualifier("model")
Model myModel;
DispatcherPortlet dispatcherPortlet;
#Test
public void testInitialize() throws Exception {
DispatcherPortlet portlet = new DispatcherPortlet() {
protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(ExplanationOfBenefitController.class));
wac.refresh();
return wac;
}
};
portlet.init(new MockPortletConfig());
MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW);
MockRenderResponse response = new MockRenderResponse();
//System.out.println("helper:"+helper);
portlet.render(request, response);
assertEquals("tableJSP", response.getContentAsString());
}
}
Can I use the autowired field created in JUNIT test class, in controller?

Related

Mockito Null Pointer Exception when initializing using #RunWith annotation when mocking

I'm using Mockito to create mock beans, and for some reason, when I initialize a mock with #RunWith(MockitoJUnitRunner.class), I get an error when I call a method from the mocked class. However, if I initialize using #BeforeEach, it works fine. to be more specific:
#RunWith(MockitoJUnitRunner.class)
class Test {
#Mock
Bean mockBean;
#Test
void testGet() {
Mockito.when(mockBean.method()).thenReturn(2);
assertEquals(2, mockBean.method());
}
The above causes a NullPointException error on the line Mockito.when(mockBean.method()).thenReturn(2);
H**owever, if I do the below:
class Test {
#Mock
Bean mockBean;
#BeforeEach
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
void testGet() {
Mockito.when(mockBean.method()).thenReturn(2);
assertEquals(2, mockBean.method());
}
the test runs just fine. I was under the impression that the two should work the same. I'd appreciate it if anyone could tell me what I am doing wrong or misunderstanding.

Spring Batch testing - Autowired bean is null

I am completely stumped. I am new to Spring Batch testing and I have found countless examples that have left me confused.
I'm trying to test a Spring Batch decider. This decider checks to see if certain JSON files exist before continuing.
To begin, I have a BatchConfiguration file marked with #Configuration in my Spring Batch project.
In the BatchConfiguration, I have a ImportJsonSettings bean which loads its properties from settings in the application.properties file.
#ConfigurationProperties(prefix="jsonfile")
#Bean
public ImportJSONSettings importJSONSettings(){
return new ImportJSONSettings();
}
When running the Spring Batch application, this works perfectly.
Next, here are the basics of the JsonFilesExistDecider , which Autowires a FileRetriever object...
public class JsonFilesExistDecider implements JobExecutionDecider {
#Autowired
FileRetriever fileRetriever;
#Override
public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) { ... }
The FileRetriever object itself Autowires the ImportJSONSettings object.
Here is the FileRetriever...
#Component("fileRetriever")
public class FileRetriever {
#Autowired
private ImportJSONSettings importJSONSettings;
private File fieldsFile = null;
public File getFieldsJsonFile(){
if(this.fieldsFile == null) {
this.fieldsFile = new File(this.importJSONSettings.getFieldsFile());
}
return this.fieldsFile;
}
}
Now for the test file. I am using Mockito for testing.
public class JsonFilesExistDeciderTest {
#Mock
FileRetriever fileRetriever;
#InjectMocks
JsonFilesExistDecider jsonFilesExistDecider;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testDecide() throws Exception {
when(fileRetriever.getFieldsJsonFile()).thenReturn(new File(getClass().getResource("/com/files/json/fields.json").getFile()));
// call decide()... then Assert...
}
}
PROBLEM... The ImportJSONSettings object that is #Autowired in the FileRetriever object is always NULL.
When calling the testDecide() method, I get a NPE since calling the getFieldsJsonFile() in FileRetriever, the ImportJSONSettings bean does not exist.
How does the ImportJSONSettings bean get properly created in the FileRetriever object so it can be used??
I have tried adding the following to my test class, but it does not help.
#Mock
ImportJSONSettings importJSONSettings;
Do I need to create it independently? How does it get injected into the FileRetriever?
Any help would be appreciated.
Try changing the #Before annotation on the setup() method to #BeforeEach like so:
#BeforeEach
void setup() {
MockitoAnnotations.initMocks(this);
}
This could also be a dependency issue. Make sure you have a recent version of io.micrometer:micrometer-core. Would you be able to share your test dependencies?
If you have the above setup correctly, you shouldn't have to worry about whether or not ImportJSONSettings is null or not as long as you have getFieldsJsonFile() stubbed correctly.

mock beans inside a method and those beans are also autowired in the same class or super class

#RunWith(SpringRunner.class)
#WebAppConfiguration
Class Test{
#Autowired
public SomeBean someBean;
#Test
public void testAccountPage2() throws Exception {
SomeBean someBean = mock(SomeBean.class);
given(someBean.getAccount(anyString())).willReturn(getCustomer());
}
Here someBean.getAccount(anyString()) is not mocking, which is calling the actual method of that bean impl. It seems it's taking the Autowired object not the mocked one.
Could anyone help me to mock beans in method level? those beans are also autowired in the same class or superclass.
Thanks
To replace a bean in the Spring container by a Mockito mock, use #MockBean.
import org.springframework.boot.test.mock.mockito.MockBean; // import to add
#RunWith(SpringRunner.class)
#WebAppConfiguration
Class Test{
#MockBean
public SomeBean someBean;
#Test
public void testAccountPage2() throws Exception {
given(someBean.getAccount(anyString())).willReturn(getCustomer());
}
}
To understand the difference between Mockito and MockBean from Spring Boot, you can refer to this question.
You need to inject the mock in order to have it working instead of autowiring
//if you are just testing bean/services normally you do not need the whole application context
#RunWith(MockitoJUnitRunner.class)
public class UnitTestExample {
#InjectMocks
private SomeBean someBean = new SomeBean();
#Test
public void sampleTest() throws Exception {
//GIVEN
given(
someBean.getAccount(
//you should add the proper expected parameter
any()
)).willReturn(
//you should add the proper answer, let's assume it is an Account class
new Customer()
);
//DO
//TODO invoke the service/method that use the getAccount of SomeBean
Account result = someBean.getAccount("");
//VERIFY
assertThat(result).isNotNull();
//...add your meaningful checks
}
}

What is sense of #Mock annotation?

I have a question about bean creation in testing of controllers. For example, there is a such test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {MainApplicationConfiguration.class, JPAConfig.class})
#WebAppConfiguration
public class TestMainController {
private MockMvc mockMvc;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(mainController).build();
}
#InjectMocks
private MainController mainController;
#Mock
private EntryService entryService;
#Autowired
DBEntryRepository repository;
#Test
public void testEntryGet() throws Exception {
List<DBEntry> response_data = new ArrayList<>();
response_data.add(new DBEntry(1, 1, "STR", "DATE"));
Mockito.when(entryService.findAllEntries())
.thenReturn(response_data);
MvcResult result = mockMvc.perform(get("/VT/entry/"))
.andExpect(status().isOk()).andReturn();
verify(entryService, times(1)).findAllEntries();
verifyNoMoreInteractions(entryService);
}
}
and a controller method mapped on
/VT/entry/
#RequestMapping(value = "/entry/", method = RequestMethod.POST)
public ResponseEntity<Void> createEntry(#RequestBody DBEntry entry, UriComponentsBuilder ucBuilder) {
System.out.println("Creating entry " + entry.getNum());
try {
entryService.saveEntry(entry);
entryService.refreshEntryService();
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<Void>(HttpStatus.BAD_REQUEST);
}
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/entry/{id}").buildAndExpand(entry.getId()).toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
EntryService is annotated with #Service annotation and MainApplicationConfiguration.class is a configuration with #EnableWebMvc and scan project for this EntryService.
by that I want to show that this controller really uses this EntryService in a real application and all are coupled by MainApplicationConfiguration.class.
Question is: Why entryService with #Mock annotation ended up in my controller code in the scope of my test execution? Shouldn't it be only for that instance only and inside of controller should be instantiated another bean(EntryService), why this annotation has mocked all occurrences of that bean (in the test scope)? I was thinking, that I should write whole other context web-context instead of MainApplicationConfiguration.class to mock it inside and substitute current definition. I am absolutely confused why this simple annotation have made such thing.
And if somebody can understand this magic, please say what is difference between #InjectMock and #Mock?
thanks for your attention! and sorry if my question is quite stupid. I am very new, it works, but I have not got magic yet.
In the documentation for #InjectMocks:
Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order
So since EntryService is a dependency of your controller, #InjectMocks will try to find a mock object of EntryService in your test class and inject it into mainController.
Note that only one of constructor injection, setter injection, or property injection will occur.
#Mock marks the fields as mock objects.
#InjectMocks injects mock objects to the marked fields, but the marked fields are not mocks.

In my JUnit test, how do I verify a Spring RedirectView?

I'm using Spring 3.2.11.RELEASE and JUnit 4.11. In a particular Spring controller, I have a method that ends thusly ...
return new ModelAndView(new RedirectView(redirectUri, true));
In my JUnit test, how do I verify return from a submission to my controller in which this RedirectView is returned? I used to use org.springframework.test.web.AbstractModelAndViewTests.assertViewName, but that only returns "null", even when a non-empty ModelAndView object is returned. Here is how I'm constructing my JUnit test ...
request.setRequestURI(“/mypage/launch");
request.setMethod("POST");
…
final Object handler = handlerMapping.getHandler(request).getHandler();
final ModelAndView mav = handlerAdapter.handle(request, response, handler);
assertViewName(mav, "redirect:/landing");
Any help on how to verify that a RedirectView comes back with the proper value is appreciatd,
As Koiter said, consider moving to spring-test a and MockMvc
It providers some methods to test controllers and requests/reponses in a declarative way
you will need a #Autowired WebApplicationContext wac;
and on your #Before method setup this to use the #WebAppConfiguration of the class.
You'll end up with something
#ContextConfiguration("youconfighere.xml")
//or (classes = {YourClassConfig.class}
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
public class MyControllerTests {
#Autowired WebApplicationContext wac
private MockMvc mockMvc;
#Before
public void setup() {
//setup the mock to use the web context
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
}
Then you just need to use the MockMvcResultMatchers to assert things
#Test
public void testMyRedirect() throws Exception {
mockMvc.perform(post("you/url/")
.andExpect(status().isOk())
.andExpect(redirectUrl("you/redirect")
}
Note: post(), status() isOk() redirectUrl() are statics imports from MockMvcResultMatchers
See more what you can match here
Considering change your tool to MockMvc.
First you should create your MockMvc based on your controller.
private MockMvc mockController;
mockController =
MockMvcBuilders.standaloneSetup(loginController).setCustomArgumentResolvers(
new ServletWebArgumentResolverAdapter(new PageableArgumentResolver())).build();
After you create that object build the request with the request information. Part of this is the assert options that are contained in the API.
mockController.perform(MockMvcRequestBuilders.get(LoginControllerTest.LOGIN_CONTROLLER_URL + "?logout=true").
principal(SessionProvider.getPrincipal("GonLu004")))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.view().name("jsp/login"))
.andExpect(MockMvcResultMatchers.model().attribute("logOutMessage", logoutMessage));
The MockMvcResultMatchers contains a method for reviewing redirect information.
MockMvc from spring is a good choice to apply your unit testing on the controller layer.

Resources