When using mockito to unit test Spring mvc controller, how to inject dao layer object. It's always giving null pointer exception with #Spy annotation when making use of SpringJUnit4ClassRunner class.
Sample code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:**/evivecare-application-context-test.xml" })
#WithMockUser(username = "admin", roles={"ADMIN"})
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class})
public class ControllerTest {
private MockMvc mockMvc;
#Mock
private SessionFactory sessionFactory;
#Mock
private Session session;
#InjectMocks
private FilterController filterController = new FilterController();
#Spy
private FilterService filterService= new FilterServiceImpl();
#Autowired
private FilterDAO filterDAO;
#Mock
private OperatorService userService;
#Mock
private EviveSpeechFilterService eviveSpeechFilterService;
private TestContextManager testContextManager;
#Before
public void setup() throws Exception {
// Process mock annotations
MockitoAnnotations.initMocks(this);
// Setup Spring test in standalone mode
this.mockMvc = MockMvcBuilders.standaloneSetup(filterController).build();
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this);
filterDAO= new FilterDAOImpl(sessionFactory);
Mockito.doReturn(session).when(sessionFactory).getCurrentSession();
}
#Test
public void testController200() throws Exception{
Mockito.when(filterService.renameList("123","sdfgh")).thenReturn(false);
Mockito.when(filterDAO.renameList("123","sdfgh")).thenReturn(false);
this.mockMvc.perform(org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post("/renameList")
.sessionAttr("filterService", filterService)
.sessionAttr("filterDAO", filterDAO)
.param("listId", "1234567")
.param("alternateName", "LIst Name"))
.andExpect(org.springframework.test.web.servlet.result.MockMvcResultMatchers.status().isOk());
}
}
In this test case, the filterService in turn calls filterDAO, which is always returning null pointer exception.
So, what can I do to resolve this issue?
FilterService is not a managed bean, you probably need to inject the dao in the constructor since it won't be autowired inside filterService.
Please refer to this question on SO for more info: Support for autowiring in a class not instantiated by spring (3)
Related
I'm trying to test a spring rest controller class using JUnit, Mockito, Spring test and Spring Security test. The following is my rest controller class for which i'm performing the test;
#RestController
public class EmployeeRestController {
#Autowired
private EmployeeService employeeService;
#PreAuthorize("hasAnyRole('ROLE_EMPSUPEADM')")
#RequestMapping(value = "/fetch-timezones", method = RequestMethod.GET)
public ResponseEntity<List<ResponseModel>> fetchTimeZones() {
List<ResponseModel> timezones = employeeService.fetchTimeZones();
return new ResponseEntity<>(timezones, HttpStatus.OK);
}
}
The following is my test class;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {SpringConfiguration.class})
#WebAppConfiguration
public class EmployeeRestControllerUnitTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Mock
private EmployeeService employeeService;
#InjectMocks
private EmployeeRestController employeeRestController;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
Mockito.reset(employeeService);
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.build();
}
#Test
#WithMockUser(roles = {"EMPSUPEADM"})
public void testFetchTimezones() {
try {
mockMvc.perform(get("/fetch-timezones"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", hasSize(4)));
verify(emploeeService, times(1)).fetchTimeZones();
verifyNoMoreInteractions(employeeService);
} catch (Exception e) {
e.printStackTrace();
}
}
}
I made the above test class by refering many tutorials. The problem is i'm not able to understand everything clearly. so, i'm having the following doubts.
I'm creating a mock of EmployeeService and injecting it into EmployeeRestController using #InjectMocks, then why i'm getting the following failure;
Wanted but not invoked:
careGroupService.fetchTimeZones();
-> at com.example.api.test
.restcontroller.EmployeeRestControllerUnitTest
.testFetchTimezones(EmployeeRestControllerUnitTest.java:73)
Actually, there were zero interactions with this mock.
How does MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); works exactly.
I know that MockMvcBuilders.standaloneSetup(employeeRestController) is for testing individual controller classes and spring configuration will not be available for this method. How can we provide spring configuraton for this method, is it possible.
Finally, how does this piece of code: Mockito.reset(employeeService); works.
1) you do verify for
verify(emploeeService, times(1)).fetchTimeZones();
but you didn't setup mock behaviour for it (before you call mockMvc.perform(get("/fetch-timezones"))).
List<ResponseModel> timezones = new ArrayList<>();
when(emploeeService.fetchTimeZones()).thenReturn(timezones );
2) create MockMvc from context. mockmvc emulates web container, use mock for all where is possible but supports http call and gave the possibility to call controller.
It stands up the Dispatcher Servlet and all required MVC components,
allowing us to test an endpoint in a proper web environment, but
without the overhead of running a server.
3) when you use:
#MockBean private EmployeeService employeeService;
you override real service. remove it from test class real service will be used in testing. Instead of use #Mock use #MockBean. #MockBean it's override by container, with #Mock you need to inject this into controller by reflection
or without spring boot with reflection:
#Before
public void init() {
MockitoAnnotations.initMocks(this);
Mockito.reset(employeeService);
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.build();
EmployeeRestController employeeRestController=
webAppContext.getBean(EmployeeRestController.class);
ReflectionTestUtils.setField(employeeRestController,
"employeeService",
employeeService);
}
4) Mockito.reset(employeeService);- you reset all behaviors that you setupped before. Mock contains information from when(), verify() and controls it , call reset - it's clean all information.
I'm following tutorials for integrating Spring docs into my project but i'm running into nullpointerexception when I run my test.
The errors go away when I take out all the document bits. So when I remove restDocumentation variable, the document bit from the setup method and the test then it passes.
Here is my test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigWebContextLoader.class, classes = { ContextConfiguration.class })
#WebAppConfiguration
public class ApiDocs {
#Rule
public RestDocumentation restDocumentation = new RestDocumentation(
"${project.basedir}/target/generated-snippets");
private RestDocumentationResultHandler document;
#Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
#Autowired
Config Config;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)).alwaysDo(this.document).build();
}
#Test
public void getConfig() throws Exception {
this.mockMvc.perform(get("/config").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andDo(document("index"));
}
}
The error that I'm getting(I've slashed out my class package due to privacy):
java.lang.NullPointerException
at org.springframework.test.web.servlet.MockMvc.applyDefualtResultActions(MockMvc.java:195)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:163)
at //.//.//.//.//.ApiDocs.getConfig(ApiDocs.java:67)
at org.springframework.test.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at
org.springframework.restdocs.RestDocumentation$1.evaluate(RestDocumentation.java:59)
at org.springframework.test.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.springframework.test.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.springframework.test.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:75)
at org.springframework.test.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:75)
at org.springframework.test.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
Nothing's assigning a value to your this.document field so it's null. You're passing that into alwaysDo which then causes a NullPointerException.
You need to configure what you want to always happen. For example by adding this to the beginning of your setUp method:
this.document = document("{method-name}",
preprocessRequest(removeHeaders("Foo")),
preprocessResponse(prettyPrint()));
There's more information about this in the documentation.
I'd like to test a Spring Boot Rest controller, which is secured using Spring security, and use mocks inside it. I have tried with Mockito, but I think any mocking tool should do the trick.
To enable Spring security in my tests, I first did as follow:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Main.class)
#TestPropertySource(value="classpath:application-test.properties")
#WebAppConfiguration
#ContextConfiguration
public class MyTest{
protected MockMvc mockMvc;
#Autowired
private WebApplicationContext wac;
#Before
public void setUp(){
mockMvc = MockMvcBuilders
.webAppContextSetup(wac)
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
}
#Test
public void doTheTest(){
mockMvc.perform(post("/user/register")
.with(SecurityMockMvcRequestPostProcessors.csrf())
.content(someContent()));
}
}
Until there, it works well.
After this step, I wished to add mocks to test my secured controller in isolation.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Main.class)
#TestPropertySource(value="classpath:application-test.properties")
#WebAppConfiguration
#ContextConfiguration
public class MyTest{
protected MockMvc mockMvc;
#Mock
private Myservice serviceInjectedInController;
#InjectMocks
private MyController myController;
#Autowired
private WebApplicationContext wac;
#Before
public void setUp(){
mockMvc = MockMvcBuilders
.webAppContextSetup(wac)
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
}
#Test
public void doTheTest(){
mockMvc.perform(post("/user/register")
.with(SecurityMockMvcRequestPostProcessors.csrf())
.content(someContent()));
}
}
Unfortunately, the mocked service is not injected in the controller, as there is nothing relating the MockMVC and the Mocks, so the mocks are not injected in the controller.
So I tried changing the configuration of the MockMVC, as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Main.class)
#TestPropertySource(value="classpath:application-test.properties")
#WebAppConfiguration
#ContextConfiguration
public class MyTest{
protected MockMvc mockMvc;
#Mock
private Myservice serviceInjectedInController;
#InjectMocks
private MyController myController;
#Before
public void setUp(){
mockMvc = MockMvcBuilders
.standAloneSetup(myController)
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
}
#Test
public void doTheTest(){
mockMvc.perform(post("/user/register")
.with(SecurityMockMvcRequestPostProcessors.csrf())
.content(someContent()));
}
}
But in this case, I have another issue. Spring security is complaining about the configuration:
java.lang.IllegalStateException: springSecurityFilterChain cannot be null. Ensure a Bean with the name springSecurityFilterChain implementing Filter is present or inject the Filter to be used.
I have no other idea to make security and mocking. Any idea? Or should I do another way?
Thanks.
By default the integration looks for a bean with the name of "springSecurityFilterChain". In the example that was provided, a standalone setup is being used which means MockMvc will not be aware of the WebApplicationContext provided within the test and thus not be able to look up the "springSecurityFilterChain" bean.
The easiest way to resolve this is to use something like this:
MockMvc mockMvc = MockMvcBuilders
// replace standaloneSetup with line below
.webAppContextSetup(wac)
.alwaysDo(print())
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
If you really want to use a standaloneSetup (doesn't really make sense since you already have a WebApplicationContext), you can explicitly provide the springSecurityFilterChain using:
#Autowired
FilterChainProxy springSecurityFilterChain;
#Before
public void startMocks(){
controller = wac.getBean(RecipesController.class);
MockMvc mockMvc = MockMvcBuilders
.standaloneSetup(controller)
.alwaysDo(print())
.apply(SecurityMockMvcConfigurers.springSecurity(springSecurityFilterChain))
.build();
MockitoAnnotations.initMocks(this);
}
I'm trying to test a method with this signature:
#Autowired
HttpSession http_Session;
#RequestMapping(method=RequestMethod.GET, value="/search/findByName")
public #ResponseBody List<Map> search(#RequestParam(value="name", required=true) String name){
Integer user_id = http_Session.getAttribute("userinfo");
}
userinfo is a class which contains informations about the user and set in session scope when the user logged in.but when I try the test :
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(locations = {
"classpath:/META-INF/applicationContext.xml"})
public class userControllerTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
}
#Test
public void userTest() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/search/findByName").param("name", "bob"))
.andDo(print())
.andExpect(MockMvcResultMatchers.status().isOk());
}
The problem is the userinfo class attribute is set in another method so when i try to access it in this method i got a NullPointerException , and with Autowiring the httpSession i got a new Session for each method i have to test.
What should i do with the session attribute, my method doesn't accept a session parameter , and for each test it create a WebApplicationContext with a new session.
Try this :
HashMap<String, Object> sessionattr = new HashMap<String, Object>();
sessionattr.put("userinfo", "XXXXXXXX");
mockMvc.perform(MockMvcRequestBuilders.get("/search/findByName").sessionAttrs(sessionattr).param("name", "bob"))
.andDo(print())
.andExpect(MockMvcResultMatchers.status().isOk());
You could also share a session across different requests:
import static org.springframework.test.web.servlet.setup.SharedHttpSessionConfigurer.sharedHttpSession;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders
.webAppContextSetup(this.webApplicationContext)
.apply(sharedHttpSession()) // use this session across requests
.build();
}
note: this session will be shared among requests performed against the same MockMvc instance only.
Am new to Spring MVC, i have written web servise using spring MVC and resteasy. My controller is working fine, now need to write testcase but i tried writtig but i never succed am also getting problem in autowiring.
#Controller
#Path("/searchapi")
public class SearchAPIController implements ISearchAPIController {
#Autowired
private ISearchAPIService srchapiservice;
#GET
#Path("/{domain}/{group}/search")
#Produces({"application/xml", "application/json"})
public Collections getSolrData(
#PathParam("domain") final String domain,
#PathParam("group") final String group,
#Context final UriInfo uriinfo) throws Exception {
System.out.println("LANDED IN get****************");
return srchapiservice.getData(domain, group, uriinfo);
}
}
can anyone give me sample code for Test case in spring mvc.
"Spring-MVC" Test case could seem like this using mock objects, for example we want to test my MyControllerToBeTest:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/spring.xml")
public class MyControllerTest {
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private MyControllerToBeTested controller;
private AnnotationMethodHandlerAdapter adapter;
#Autowired
private ApplicationContext applicationContext;
#Before
public void setUp() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
response.setOutputStreamAccessAllowed(true);
controller = new MyControllerToBeTested();
adapter = new AnnotationMethodHandlerAdapter();
}
#Test
public void findRelatedVideosTest() throws Exception {
request.setRequestURI("/mypath");
request.setMethod("GET");
request.addParameter("myParam", "myValue");
adapter.handle(request, response, controller);
System.out.println(response.getContentAsString());
}
}
but i don't have any experience with REST resource testing, in your case RestEasy.
If you want to test the full service inside the container you can have a look at the REST Assured framework for Java. It makes it very easy to test and validate HTTP/REST-based services.