Spring MockMvc test: Null pointer Exception - spring-mvc

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.

Related

#Value not visible inside #component filter during tests

I created filter which logging and saving all requests, this is part of this:
#Component
public class RequestFilter extends OncePerRequestFilter {
#Value("${app.endpoint}")
private String requestMapping;
private final RequestRepository requestRepository;
#Autowired
public RequestFilter(RequestRepository requestRepository) {
this.requestRepository = requestRepository;
}
....
}
When app is running requestMapping is properly readed from spring context, but
when I created test for that filter requestMapping is null
#SpringBootTest
#RunWith(SpringRunner.class)
#AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2)
#ContextConfiguration(classes = {MyApplication.class})
#AutoConfigureMockMvc
#ActiveProfiles("test")
public class FilterTest {
#Autowired
private WebApplicationContext webApplicationContext;
#Autowired
private RequestRepository requestRepository;
#Autowired
protected MockMvc mockMvc;
#Before
public void setup() {
RequestFilter rpmRequestFilter = new RequestFilter(this.requestRepository);
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.addFilter(invalidVpmRequestFilter)
.build();
}
}
And of course in application-test.properties I have configured this property:
app.endpoint=/log/save
Does someone know where the problem can be? Why this is doesnt work in tests?
As M. Deinum pointed out, the problem is that you are creating an instance of RequestFilter and if you want Spring to inject components (#Autowired) or propoerties (#Value) in it, you have to let Spring handle the instantiation as follow :
#....
public class FilterTest {
....
#Autowired
RequestFilter requestFilter;
#Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.addFilter(requestFilter)
.build();
}
}

Mockito failure: Actually, there were zero interactions with this mock

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.

Spring mvc unit test controller inject dao object using mockito

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)

Test Spring Mvc controller and inject static class

The following code is the standard method to write a JUnit test for a Mvc controller.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = ApplicationTestCassandra.class)
#WebAppConfiguration
public class TestControllerTests {
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
#Before
public void setup() throws Exception {
this.mockMvc = webAppContextSetup(webApplicationContext).build();
}
#Test
public void testupTimeStart() throws Exception {
this.mockMvc.perform(get("/uptime"))
.andExpect(status().isOk());
}
}
This works fine, but I would like to replace an autowired class with a special class for testing. The class CassandraSimpleConnection is injected via #Autowired in my controller.
I have tried several approaches, but no luck.
The following code fails because of an Mvc 404 error, because I guess my application with the REST interface is not running at all.
#RunWith(SpringJUnit4ClassRunner.class)
//ApplicationTestCassandra is SpringBoot application startpoint class with #SpringBootApplication annotation
//#ContextConfiguration(classes = ApplicationTestCassandra.class, loader = AnnotationConfigContextLoader.class)
#ContextConfiguration(loader = AnnotationConfigWebContextLoader.class)//, classes = {ApplicationTestCassandra.class})
#WebAppConfiguration
public class TestControllerTests {
#Service
#EnableWebMvc
#ComponentScan(basePackages={"blabla.functionalTests"})
static class CassandraSimpleConnection {
public Metadata testConnection(TestConfiguration configuration) {
Metadata metadata = null;
// return metadata;
throw new RuntimeException("Could not connect to any server");
}
}
If I use
#ContextConfiguration(loader = AnnotationConfigWebContextLoader.class, classes = {ApplicationTestCassandra.class})
CassandraSimpleConnection is not replaced with my static class.
Could somebody help me please? The documentation about the annotations is quite confusing.
Read the comments and here is the solution:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = { MyApplication.class })
public class MyTests {
#MockBean
private MyBeanClass myTestBean;
#Before
public void setup() {
...
when(myTestBean.doSomething()).thenReturn(someResult);
}
#Test
public void test() {
// MyBeanClass bean is replaced with myTestBean in the ApplicationContext here
}
}

How to write a mockito test case for ResourceAssembler with in Spring Hateos?

I am trying to write a unit test for the below Assembler but i keep getting Could not find current request via RequestContextHolder. Is this being called from a Spring MVC handler?. I wanted to know how i can mock out the resource creation?
#Component
public class LoginResourceAssembler extends ResourceAssemblerSupport<User, ResourceSupport> {
public LoginResourceAssembler() {
super(User.class, ResourceSupport.class);
}
#Override
public ResourceSupport toResource(User user) {
ResourceSupport resource = new ResourceSupport();
final String id = user.getId();
resource.add(linkTo(MyAccountsController.class).slash(id).slash("accounts").withRel("accounts"));
return resource;
}
}
Instead of changing from a plain unit test to a IMO integration test (given dependency of the spring framework) you could do something like:
#RunWith(MockitoJUnitRunner.class)
public class LoginResourceAssemblerTest {
#InjectMocks
private LoginResourceAssembler loginResourceAssembler;
#Before
public void setup() {
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(new MockHttpServletRequest()));
}
#Test
public void testToResource() {
//...
}
}
I was seeing the error Could not find current request via RequestContextHolder. Is this being called from a Spring MVC handler because my test class was annotated with #RunWith(MockitoJUnitRunner.class) and this was not injecting the controller.
To fix this error, i annotated my test case with
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
A working test case in my case
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class LoginResourceAssemblerTest {
#Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
#InjectMocks
private LoginResourceAssembler loginResourceAssembler;
#Before
public void setUp() {
initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
#Test
public void testToResource() {
User user = new User();
user.setId("1234");
ResourceSupport resource = loginResourceAssembler.toResource(user);
assertEquals(1,resource.getLinks().size());
assertEquals("accounts",resource.getLinks().get(0).getRel());
assertTrue(resource.getLinks().get(0).getHref().contains("accounts"));
}
}

Resources