I want to test my controller with the help of JUnit. I am new to this. I have written some code for this but it is not coming to my function listCard. My controller is:
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
#RequestMapping("/v1/card")
#Configuration
public class CardManagementController {
private final static Logger LOG = LoggerFactory
.getLogger(CardManagementController.class);
#Autowired
ICardService cardService;
#RequestMapping(value = "", produces = RestURIConstants.APPLICATION_JSON, method = RequestMethod.GET)
public #ResponseBody GetCardResponse getCard(
#ModelAttribute #Valid GetCardRequest request, BindingResult results)
throws RuntimeException, ValidationException {
if (results.hasErrors()) {
LOG.error("error occured occur while fetching card response");
throw new ValidationException(
"Error Occoured while validiating card request");
}
GetCardResponse response = null;
response = cardService.getCard(request);
return response;
}
#RequestMapping(value = "", produces = RestURIConstants.APPLICATION_JSON, method = RequestMethod.POST)
public #ResponseBody AddCardResponse addCard(
#ModelAttribute AddCardRequest request, BindingResult results)
throws RuntimeException, ValidationException {
if (results.hasErrors()) {
LOG.error("error occured while adding the card");
throw new ValidationException(
"Error Occoured while validiating addcard request");
}
LOG.debug("add Card with POST method");
AddCardResponse response = null;
response = cardService.addCard(request);
return response;
}
#RequestMapping(value = "", produces = RestURIConstants.APPLICATION_JSON, method = RequestMethod.DELETE)
public #ResponseBody DeleteCardResponse deleteCard(
#ModelAttribute #Valid DeleteCardRequest request,
BindingResult results) throws RuntimeException, ValidationException {
if (results.hasErrors()) {
LOG.debug("error occured while delting the card");
throw new ValidationException(
"Error Occoured while validiating delete card request");
}
DeleteCardResponse response = null;
response = cardService.deleteCard(request);
return response;
}
#RequestMapping(value = RestURIConstants.LISTCARD, produces = RestURIConstants.APPLICATION_JSON, method = RequestMethod.GET)
public #ResponseBody ListCardResponse listCard(
#ModelAttribute #Valid ListCardRequest request) throws RuntimeException, ValidationException {
ListCardResponse response = null;
response = cardService.listCards(request);
return response;
}
#ExceptionHandler({ ValidationException.class})
#ResponseBody
public CPPException handleValidationException(ValidationException ex) {
LOG.error("Exception occoured",ex);
CPPException exception = new CPPException(ex.getMessage());
exception.setStatus(500);
return exception;
}
#ExceptionHandler({RuntimeException.class})
#ResponseBody
public CPPException handleException(RuntimeException ex) {
LOG.error("Exception occoured", ex);
CPPException exception = new CPPException("Internal Server Error");
exception.setStatus(500);
return exception;
}
}
and I have written the following code for testing:
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.my.cpp.controller.CardManagementController;
import com.my.cpp.request.ListCardRequest;
import com.my.cpp.service.impl.CardServiceImpl;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:/spring/application-context.xml"})
public class CardApiTest {
private MockMvc mockMvc;
//#Autowired
private CardManagementController cm=new CardManagementController();
#Autowired
private CardServiceImpl cmr;
#Before
public void setUp() throws Exception {
mockMvc= MockMvcBuilders.standaloneSetup(cm).build();
}
#Test
public void testList() throws Exception{
final ListCardRequest lr=new ListCardRequest();
this.mockMvc.perform(get("/v1/card/list?"));
}
}
First - Remove the #Configuration annotation from your controller. It doesn't belong here.
Second - Consider using Mockito while testing, since you have a service injected in your controller. Your updated test class should look something similar as below
#RunWith(MockitoJUnitRunner.class)
public class CardApiTest {
private MockMvc mockMvc;
#InjectMocks
private CardManagementController cm;
#Mock
private ICardService cardService;
#Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(cm).build();
// Instantiate cardListRequest and cardListResponse here
when(cardService.listCards(cardListRequest)).thenReturn(cardListResponse);
}
#Test
public void testList() throws Exception{
this.mockMvc.perform(get("/v1/card/list?"));
}
}
Let know in comments if you need further info / assistance.
Related
This is the Controller as it appears at the moment.
import com.myorg.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
#Controller
public class MyController {
private final MyService myService;
#Autowired
public MyController(MyService myService) {
this.myService = myService;
}
#GetMapping(value = "/my/homepage")
public String someMethod(ModelMap model, Authentication authentication) {
myService.doSomething(authentication);
return "homepage";
}
}
Here is the Controller Advice to handle exceptions
#ExceptionHandler(HttpStatusCodeException.class)
public ModelAndView handleException(HttpServletRequest req, HttpStatusCodeException ex) {
log.error(ex.getMessage(), ex);
ModelAndView mav = new ModelAndView();
// do stuff
return mav;
}
And this is the current test, which works fine
import com.myorg.service.MyService
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.security.test.context.support.WithMockUser
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.MvcResult
import org.springframework.test.web.servlet.setup.MockMvcBuilders
import org.springframework.web.context.WebApplicationContext
import spock.lang.Specification
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
#SpringBootTest
class MyControllerSpec extends Specification {
#Autowired
private WebApplicationContext webApplicationContext
#SpringBean
private MyService myService = Mock()
#WithMockUser(username = "test#email.com", roles = ["USER"])
def "MyController(test=should not authenticate)"() {
setup:
def notAuthorizedException = new HttpClientErrorException(HttpStatus.UNAUTHORIZED, "blah", null, Charset.defaultCharset())
MockMvc mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(SecurityMockMvcConfigurers.springSecurity())
.build()
myService.doSomething(_) >> { throw notAuthorizedException }
when:
MvcResult mvcResult = mvc.perform(get("/my/homepage"))
.andExpect(status().is3xxRedirection())
.andReturn()
then:
mvcResult.response.status == 302
mvcResult.modelAndView.viewName == "redirect:/my/login?logout"
}
}
The test passes successfully in that the mock throws the HttpClientErrorException, which the advice catches and then redirects the user to a logout page.
But when I replace the MyService member in the MyController class with a class that implements an interface, the test fails because the HttpClientErrorException is no longer being caught by the advice and instead is being thrown as a nested exception.
Here is the new Controller
import com.myorg.service.MyServiceThatImplementsAnInterface;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
#Controller
public class MyController {
private final MyInterface myInterface;
#Autowired
public MyController(MyInterface myInterface) {
this.myInterface = myInterface;
}
#GetMapping(value = "/my/homepage")
public String someMethod(ModelMap model, Authentication authentication) {
myInterface.doSomething(authentication);
return "homepage";
}
}
Here is the interface implementation
#Component("myInterface")
public class MyServiceThatImplementsAnInterfaceImpl implements MyInterface {
private final SomeComponent someComponent;
public MyServiceThatImplementsAnInterfaceImpl(SomeComponent comeComponent) {
this.someComponent = someComponent;
}
#Override
public void doSomething(Authentication authenticationToken) {
someComponent.doSomethingElse();
}
}
And here is the new test
#SpringBootTest
class MyControllerSpec extends Specification {
#Autowired
private WebApplicationContext webApplicationContext
#SpringBean
private MyServiceThatImplementsAnInterfaceImpl myServiceThatImplementsAnInterface = Mock()
#WithMockUser(username = "test#email.com", roles = ["USER"])
def "MyController(test=should not authenticate)"() {
setup:
def notAuthorizedException = new HttpClientErrorException(HttpStatus.UNAUTHORIZED, "blah", null, Charset.defaultCharset())
MockMvc mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(SecurityMockMvcConfigurers.springSecurity())
.build()
myServiceThatImplementsAnInterface.doSomething(_) >> { throw notAuthorizedException }
when:
MvcResult mvcResult = mvc.perform(get("/my/homepage"))
.andExpect(status().is3xxRedirection())
.andReturn()
then:
mvcResult.response.status == 302
mvcResult.modelAndView.viewName == "redirect:/my/login?logout"
}
}
Here is the failing test stack trace
Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
at app//org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at app//org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at app//javax.servlet.http.HttpServlet.service(HttpServlet.java:497)
at app//org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at app//org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)
at app//javax.servlet.http.HttpServlet.service(HttpServlet.java:584)
at app//org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
at app//org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at app//org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:337)
at app//org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
at app//org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
at app//org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at app//org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
at app//org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
at app//org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at app//org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)
at app//org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
at app//org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at app//org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)
at app//org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at app//org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
at app//org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at app//org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at app//org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at app//org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:219)
at app//org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213)
at app//org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at app//org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
at app//org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
at app//org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at app//org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117)
at app//org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at app//org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at app//org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
at app//org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
at app//org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at app//org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at app//org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
at app//org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
at app//org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at app//org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
at app//org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at app//org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
at app//org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:221)
at app//org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186)
at app//org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurer$DelegateFilter.doFilter(SecurityMockMvcConfigurer.java:132)
at app//org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at app//org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201)
at com.myorg.controller.MyControllerSpec.<where my test is>
Caused by: org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
at com.myorg.controller.MyControllerSpec.<where my test is>
Any help is appreciated
Problem solved and, as with about 90% of these kinds of problems, the error was simple to fix. In my test class, I simply hadn't assigned the exception handler class to the MockMvc.
def "MyController(test=should not authenticate)"() {
setup:
Authentication authentication = //Just mock out an Authentication object here
def notAuthorizedException = //As before, just mock out an exception
myInterface.doSomething(_) >> { throw notAuthorizedException }
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver()
viewResolver.setPrefix("prefix")
MyController myController = new MyController(myServiceThatImplementsAnInterface)
MockMvc mockMvc = MockMvcBuilders
.standaloneSetup(myController)
.setControllerAdvice(new MyExceptionHandler())
.setViewResolvers(viewResolver)
.build()
when:
MvcResult mvcResult = mockMvc.perform(get("/my/homepage")
.principal(authentication))
.andExpect(status().is3xxRedirection())
.andReturn()
then:
mvcResult.response.status == 302
mvcResult.modelAndView.viewName == "redirect:/app/login?logout"
}
#ControllerAdvice(assignableTypes = MyInterface.class)
public class MyExceptionHandler {
#ExceptionHandler(HttpStatusCodeException.class)
public ModelAndView handleException(HttpServletRequest req, HttpStatusCodeException ex) {
log.error(ex.getMessage(), ex);
ModelAndView mav = new ModelAndView();
// do stuff
return mav;
}
}
I have done a Spring Mvc application and I have been trying to write some integration tests, but I keep getting errors. Here is my AgentService:
#Service
public class AgentService {
#Autowired
private AgentRepository agentRepository;
#Autowired
private AgencyRepository repoAg;
#Autowired
private AgentMapper mapper;
public List<AgentDto> listByAgency(Long id) {
List<Agent> agents = agentRepository.findAll().stream().filter(ag -> ag.getAgency().getId().equals(id)).collect(Collectors.toList());
List<AgentDto> mappedAgents = agents.stream().map(agent -> mapper.mapToDto(agent)).collect(Collectors.toList());
return mappedAgents;
}
}
And my AgentController:
#Controller
public class AgentController {
#Autowired
private AgentService agentService;
#GetMapping("/viewAgentsPage/{id}")
public String viewAgentsPage(#PathVariable(value = "id") Long id, Model model) {
model.addAttribute("listAgents", agentService.listByAgency(id));
return "agents";
}
}
This is the test I've written:
package com.example.awbdproject.controller;
import com.example.awbdproject.models.Agency;
import com.example.awbdproject.models.Agent;
import com.example.awbdproject.services.AgentService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.ui.Model;
import static org.mockito.Mockito.doReturn;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import java.util.ArrayList;
import java.util.List;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
#SpringBootTest
#AutoConfigureMockMvc
public class AgentControllerTest {
#Autowired
MockMvc mockMvc;
#MockBean
AgentService agentService;
#MockBean
Model model;
#Test
#WithMockUser
public void showAgentsByAgency() throws Exception {
List<AgentDto> savedAgents = new ArrayList<AgentDto>();
Long id = 1L;
Agency agencyTest = new Agency();
agencyTest.setId(id);
AgentDto agentTest = new AgentDto();
agentTest.setId(1L);
agentTest.setFirstName("test");
agentTest.setLastName("test");
agentTest.setEmail("email#gmail.com");
agentTest.setAgency(agencyTest);
savedAgents.add(agentTest);
when(agentService.listByAgency(id)).thenReturn(savedAgents);
mockMvc.perform(get("/viewAgentsPage/{id}", "1"))
.andExpect(status().isOk())
.andExpect(view().name("agents"))
.andExpect(model().attribute("listAgents", savedAgents))
.andExpect(content().contentType("text/html;charset=UTF-8"));
}
When I run the test I'm getting this error:
MockHttpServletRequest:
HTTP Method = GET
Request URI = /viewAgentsPage/1
Parameters = {}
Headers = []
Body = null
Session Attrs = {SPRING_SECURITY_SAVED_REQUEST=DefaultSavedRequest [http://localhost/viewAgentsPage/1]}
Handler:
Type = null
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 302
Error message = null
Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY", Location:"http://localhost/login"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = http://localhost/login
Cookies = []
What seems to be the issue here? I have never used Mockito and can't seem to wrap my head around it. I think it might have something to do with Spring Security. If it helps, this is my security configuration:
#Override
protected void configure(HttpSecurity http) throws Exception{
http.authorizeRequests().antMatchers(
"/register/**",
"/js/**",
"/css/**",
"/img/**"
).permitAll().anyRequest().authenticated()
.and().formLogin().loginPage("/login")
.permitAll()
.and().logout().invalidateHttpSession(true).clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout").permitAll();
}
I am learning java and using spring boot to develop web app. I am using #controllerAdvice to catch all the exceptions but none of my exceptions is being intercepted by it. I am using spring boot 2.6.2. git repo https://github.com/jitenderchand1/java-microservices
Controller file
package com.learning.rest.webservices.restfulwebservices.user;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
#RequestMapping("/user-service")
public class UserController {
#Autowired
private UserDaoService service;
#GetMapping(path = "/users")
public List<User> retrieveAllUser() {
return service.getAllUser();
}
#GetMapping(path = "/users/{id}")
public User retrieveOneUser(#PathVariable Integer id) {
User user = service.fineOne(id);
if(user == null){
throw new UserNotFoundException("id -" + id);
//throw new Exception();
}
return user;
}
#PostMapping(path = "/user/save")
public ResponseEntity<User> saveUser(#RequestBody User user) {
User savedUser = service.save(user);
return new ResponseEntity(savedUser, HttpStatus.CREATED);
}
}
custom Exception handler
package com.learning.rest.webservices.restfulwebservices.user;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import java.util.Date;
#ControllerAdvice
#RestController
public class CustomException extends ResponseEntityExceptionHandler {
#ExceptionHandler(Exception.class)
public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), "I messed up", request.getDescription(true));
return new ResponseEntity<>(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
#ExceptionHandler(UserNotFoundException.class)
public final ResponseEntity<Object> handleUserNotFoundException(UserNotFoundException ex, WebRequest request) {
ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), "You are not from this world",
request.getDescription(false));
return new ResponseEntity(exceptionResponse, HttpStatus.NOT_FOUND);
}
}
Background: Search form in a webapp, with an auto-complete/suggestion. Using jQuery's autocomplete, suggestions are shown after typing a few characters. These suggesitons are retrieved as JSON data from one of the webapp's controllers.
Issue: I am testing the application via the HtmlUnit Integration of Spring Test, which works fine for Text/Html Pages, but for the JSON responses here, the setup seems to fail (see error below).
Manually testing (the actual webapp) via Browser works and fetching JSON from "real" pages works as well ( see "json()" test) -> Should testing JSON responses work via HtmlUnit / Spring Test setup and if yes, what am I doing wrong?
Update (2017-06-21):
Using
#ResponseBody String
and building the JSON "manually" (not letting Spring automagically doing it) works; not really what I wanted, but at least I can properly test it this way ...
Test:
package my.project;
import com.gargoylesoftware.htmlunit.*;
import org.junit.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.*;
import org.springframework.test.*;
import org.springframework.web.context.support.GenericWebApplicationContext;
import javax.servlet.ServletException;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {TestWebAppConfig.class,
// avoid context caching
MyControllerIT.class})
#WebAppConfiguration
public class MyControllerIT {
protected static final String SERVER_URL = "http://localhost";
protected WebClient webClient;
protected MockHttpServletRequest request;
protected MockHttpServletResponse response;
#Autowired
protected GenericWebApplicationContext webApplicationContext;
#Before
public void setUp() throws Exception {
this.request = new MockHttpServletRequest();
this.request.setServerName("Gondor.Osgiliath");
this.response = new MockHttpServletResponse();
this.webClient = this.initClient();
}
protected final WebClient initClient() throws ServletException {
DefaultMockMvcBuilder mockMvcBuilder = MockMvcBuilders.webAppContextSetup(this.webApplicationContext);
MockMvc mockMvc = mockMvcBuilder.build();
WebClient webClient = new WebClient();
webClient.setWebConnection(new MockMvcWebConnection(mockMvc));
return webClient;
}
// https://stackoverflow.com/questions/2932857/html-handling-a-json-response
#Test
public void json() throws Exception {
webClient = new WebClient(BrowserVersion.INTERNET_EXPLORER, "some.proxy", 7890);
Page page = webClient.getPage("https://stackoverflow.com/users/flair/97901.json");
WebResponse webResponse = page.getWebResponse();
String contentType = webResponse.getContentType();
String contentAsString = webResponse.getContentAsString();
}
#Test
public void suggestShouldReturnJSON() throws Exception {
Page page = webClient.getPage(SERVER_URL + MyController.SUGGEST_URL + "?term=asdf");
WebResponse webResponse = page.getWebResponse();
String contentType = webResponse.getContentType();
String contentAsString = webResponse.getContentAsString();
}
#Test
public void suggestShouldReturnJSONViaMockMvc() throws Exception {
MockMvc springMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
ResultActions resultActions = springMvc.perform(MockMvcRequestBuilders
.get(MyController.SUGGEST_URL + "?term=asdf")
.accept(MediaType.APPLICATION_JSON_VALUE));
resultActions.andDo(MockMvcResultHandlers.print());
}
}
Controller:
package my.project;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Arrays;
import java.util.List;
#Controller
public class MyController {
public static final String SUGGEST_URL = "/suggest";
//http://api.jqueryui.com/autocomplete/#option-source
#RequestMapping(value = {SUGGEST_URL,}, produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody
List<Suggestion> suggest(#RequestParam(name = "term") String term) {
return Arrays.asList(new Suggestion("label1", "value1"), new Suggestion("label2", "value2"));
}
}
Config (Thymeleaf omitted for the moment):
package my.project;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#EnableWebMvc
#ComponentScan(basePackages = {"my.project.*",})
#Configuration
#Import(ThymeleafConfig.class)
abstract class TestWebAppConfig extends WebMvcConfigurerAdapter {
}
Error:
com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException: 406 Not Acceptable for http://localhost/suggest?term=asdf
at com.gargoylesoftware.htmlunit.WebClient.throwFailingHttpStatusCodeExceptionIfNecessary(WebClient.java:571)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:396)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:304)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:451)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:436)
at my.project.MyControllerIt.suggestShouldReturnJSON(MyControllerIt.java:
...
I'm trying to migrate to RestAssuredMockMvc from regular MockMvc for a Spring Web Application, but I ran into a problem:
When trying to test against a simple resource, I get a 404. I wrote an equivalent MockMvc test as well, which succeeds.
Here are the two tests:
RestAssured:
package at.mycompany.iad.remote.internalorg.v1.controller;
import at.mycompany.iad.remote.internalorg.v1.resource.OrgProfileResource;
import at.mycompany.iad.remote.internalorg.v1.testconfig.TestConfig;
import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.context.WebApplicationContext;
import static io.restassured.RestAssured.when;
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestConfig.class)
public class OrgProfileControllerITRestAssured {
#Autowired
private WebApplicationContext context;
#Before
public void initRestAssured() {
RestAssuredMockMvc.webAppContextSetup(context);
// RestAssuredMockMvc.standaloneSetup(new OrgProfileResource(null)); //I tried this too, same result
}
#Test
public void getAd() throws Exception {
when()
.get("/examplepartnerid/profile")
.then()
.statusCode(HttpStatus.OK.value());
}
}
And MockMvc:
package at.mycompany.iad.remote.internalorg.v1.controller;
import at.mycompany.iad.remote.internalorg.v1.testconfig.TestConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestConfig.class)
public class OrgProfileControllerITMockMvc {
#Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
#Before
public void setUp() throws Exception {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
#Test
public void testGet() throws Exception {
MvcResult mvcResult = this.mockMvc.perform(
get("/examplepartnerid/profile"))
.andExpect(status().is(200)).andReturn();
}
}
And the controller being tested:
package at.mycompany.iad.remote.internalorg.v1.resource;
import at.mycompany.iad.remote.internalorg.v1.controller.OrgProfileController;
import at.mycompany.iad.remote.internalorg.v1.dto.OrgProfileDto;
import io.swagger.annotations.*;
import no.finntech.kernel.framework.exception.SystemException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
#RestController
#RequestMapping(value = "/{partnerId}/profile")
#Api(description = "Operations used for updating organisation services")
public class OrgProfileResource {
private final OrgProfileController controller;
#Autowired
public OrgProfileResource(OrgProfileController controller) {
this.controller = controller;
}
#RequestMapping(method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
#ApiOperation(value = "get organisation profile")
#ApiResponses({
#ApiResponse(code = 200, message = "returns organisation profile for supplied partnerId"),
#ApiResponse(code = 404, message = "no organisation found with supplied partnerId")
})
public ResponseEntity<OrgProfileDto> getOrgProfile(
#ApiParam(required = true) #PathVariable String partnerId
) throws SystemException {
OrgProfileDto orgProfile = controller.getOrgProfile(partnerId);
return ResponseEntity.status(HttpStatus.OK).body(orgProfile);
}
#RequestMapping(method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.ACCEPTED)
#ApiOperation(value = "get organisation services")
#ApiResponses({
#ApiResponse(code = 204, message = "saved organisation services for supplied partnerId"),
#ApiResponse(code = 404, message = "no organisation found with supplied partnerId")
})
public void postOrgProfileServices(
#ApiParam(required = true) #PathVariable String partnerId,
#RequestBody OrgProfileDto requestDto
) throws SystemException {
controller.saveOrgProfile(partnerId, requestDto);
}
#RequestMapping(value = "/image", method = RequestMethod.POST, headers = "content-type=multipart/form-data", consumes = "multipart/form-data")
#ApiOperation(value = "Sets an image to existing organisation")
#ApiResponses({
#ApiResponse(code = 201, message = "The reference to the image within mycompany IAd system"),
#ApiResponse(code = 404, message = "no organisation found for given org-name")
})
#ResponseStatus(HttpStatus.CREATED)
public ResponseEntity addImageToProfile(
#ApiParam(required = true) #PathVariable String partnerId,
HttpServletRequest request) throws IOException, SystemException {
controller.saveImage(partnerId, request);
return ResponseEntity.status(202).build();
}
}