Is there any way to test this using JUnit and Mockito?
Below is a method that I want to test
#RequestMapping(value = "/logout", method = RequestMethod.GET)
public String logoutPage(HttpServletRequest request, HttpServletResponse response)
{
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null)
{
new SecurityContextLogoutHandler().logout(request, response, auth);
}
return "redirect:/login?logout";
}
Test for logout
#Test
public void testLogoutPage() throws Exception
{
MockHttpServletRequestBuilder requestBuilder = get("/logout");
MockMvcBuilders.standaloneSetup(this.loginController)
.build()
.perform(requestBuilder)
.andExpect(status().isFound())
.andExpect(MockMvcResultMatchers.model().size(0))
.andExpect(view().name("redirect:/login?logout"))
.andExpect(MockMvcResultMatchers.redirectedUrl("/login?logout"));
}
Test covers everything except.
new SecurityContextLogoutHandler().logout(request, response, auth);
I tried some assertions, but always get NullPointerException.
Related
I'm trying to unit test my controller and the specific case which is : my service return a Mono.Empty, I throw a NotFoundException and I wan't to make sure I'm getting a 404 exception
here's my controller :
#GetMapping(path = "/{id}")
public Mono<MyObject<JsonNode>> getFragmentById(#PathVariable(value = "id") String id) throws NotFoundException {
return this.myService.getObject(id, JsonNode.class).switchIfEmpty(Mono.error(new NotFoundException()));
}
Here's my controller advice :
#ControllerAdvice
public class RestResponseEntityExceptionHandler {
#ExceptionHandler(value = { NotFoundException.class })
protected ResponseEntity<String> handleNotFound(SaveActionException ex, WebRequest request) {
String bodyOfResponse = "This should be application specific";
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Resource not found");
}
}
and my test :
#Before
public void setup() {
client = WebTestClient.bindToController(new MyController()).controllerAdvice(new RestResponseEntityExceptionHandler()).build();
}
#Test
public void assert_404() throws Exception {
when(myService.getobject("id", JsonNode.class)).thenReturn(Mono.empty());
WebTestClient.ResponseSpec response = client.get().uri("/api/object/id").exchange();
response.expectStatus().isEqualTo(404);
}
I'm getting a NotFoundException But a 500 error not a 404 which mean my advice hasn't been called
stack trace :
java.lang.AssertionError: Status expected:<404> but was:<500>
> GET /api/fragments/idFragment
> WebTestClient-Request-Id: [1]
No content
< 500 Internal Server Error
< Content-Type: [application/json;charset=UTF-8]
Content not available yet
any idea ?
I believe you can delete this controller advice and just have the following:
#GetMapping(path = "/{id}")
public Mono<MyObject<JsonNode>> getFragmentById(#PathVariable(value = "id") String id) {
return this.myService.getObject(id, JsonNode.class)
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND)));
}
As for ResponseEntityExceptionHandler, this class is part of Spring MVC so I don't think you should use it in a WebFlux application.
I have a Spring Boot Filter that I'm using to authenticate using Jwt. If successful, everything works great and I send out a Json response of my design. However, if the Authorization header is missing or incorrect, I throw a ServletException with a custom message. This results in an ugly Json that looks like this:
{
"timestamp":1453192910756,
"status":500,
"error":"Internal Server Error",
"exception":"javax.servlet.ServletException",
"message":"Invalid Authorization header.",
"path":"/api/test"
}
I wish to customize this Json so it takes the standard form I'm using for all my other responses.
My Filter code is here:
public class JwtFilter extends GenericFilterBean {
#Override
public void doFilter(final ServletRequest req,
final ServletResponse res,
final FilterChain chain) throws IOException, ServletException {
System.out.println("JwtFilter");
final HttpServletRequest request = (HttpServletRequest) req;
final String authHeader = request.getHeader("Authorization");
if (authHeader == null) {
throw new ServletException("Missing Authorization header.");
}
if (!authHeader.startsWith("Bearer ")) {
throw new ServletException("Invalid Authorization header.");
}
final String token = authHeader.substring(7);
try {
final Claims claims = Jwts.parser().setSigningKey("secretkey")
.parseClaimsJws(token).getBody();
request.setAttribute("claims", claims);
}
catch (final SignatureException e) {
throw new ServletException("Invalid token.");
}
chain.doFilter(req, res);
}
}
I tried using a wrapper to wrap the response but that didn't work. Another SO post said the response was not changeable but that wouldn't even make sense.
I think the correct way would be to edit the ServletResponse res but I couldn't get it to work.
Thanks!
EDIT: Kind of hacky but it works. If there's a better way, please answer:
public class JwtFilter extends GenericFilterBean {
#Override
public void doFilter(final ServletRequest req,
final ServletResponse res,
final FilterChain chain) throws IOException, ServletException {
System.out.println("JwtFilter");
final HttpServletRequest request = (HttpServletRequest) req;
final String authHeader = request.getHeader("Authorization");
if (authHeader == null) {
res.setContentType("application/json;charset=UTF-8");
res.getWriter().write(ExceptionCreator.createJson("Missing Authorization header."));
return;
}
if (!authHeader.startsWith("Bearer ")) {
res.setContentType("application/json;charset=UTF-8");
res.getWriter().write(ExceptionCreator.createJson("Invalid Authorization header."));
return;
}
final String token = authHeader.substring(7);
try {
final Claims claims = Jwts.parser().setSigningKey("secretkey")
.parseClaimsJws(token).getBody();
request.setAttribute("claims", claims);
}
catch (Exception f) {
res.setContentType("application/json;charset=UTF-8");
res.getWriter().write(ExceptionCreator.createJson("Invalid token."));
return;
}
chain.doFilter(req, res);
}
}
In general, wrapping the response and then modifying the response output stream after the call to doFilter is the correct approach, e.g.
PrintWriter out = response.getWriter();
CharResponseWrapper wrapper = new CharResponseWrapper(
(HttpServletResponse)response);
chain.doFilter(request, wrapper);
CharArrayWriter caw = new CharArrayWriter();
caw.write("your json");
response.setContentLength(caw.toString().getBytes().length);
out.write(caw.toString());
out.close();
Taken from Oracle JavaEE 5 Tutorial
Nevertheless, your usecase seems more appropriate for being dealt with in a RestController handler method, possibly in conjunction with an #ExceptionHandler(ServletException.class) annotated method. This would be a more generic approach that allows you to harness the power of Spring's content negotiation to deal with the JSON serialization.
This is my api i have used Jersey and spring boot.The api is working fine producing correct response and I want to write unit test case for checking api using Junit.
#POST
#Path("/trip/create")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response createTrip(Trip pObjTrip, #HeaderParam("Auth-Token") String pAuthToken) {
Response lRetVal = new Response();
appLog.info(String.format("Creating a trip with [%s]", pObjTrip));
try {
User lObjUser = validateUser(pAuthToken, lRetVal);
if(lObjUser == null) {
} else if (StringUtils.isEmpty(pObjTrip.getTripName())) {
lRetVal.setResult(ResponseIds.API_RESULT_INSUFFICIENT_INFO);
lRetVal.setMessage("All information are not provided");
} else {
lObjUser.setEnabled(true);
pObjTrip.setCreatedBy(lObjUser);
pObjTrip.setCreateTime(Calendar.getInstance());
pObjTrip.setTripStatus(Trip.TRIP_STATUS_CREATED);
m_cObjTripService.saveAndFlush(pObjTrip);
lRetVal.setResult(ResponseIds.API_RESULT_SUCCESS);
lRetVal.setValue(pObjTrip);
}
} catch (Exception ex) {
appLog.warn(ex.toString(), ex);
}
return lRetVal;
}
I have written the test case after searching But getting 400 bad request for(http://localhost:8080/api/trphpr/trip/create).
#After(value = "http://localhost:8080/api/trphpr/trip/create")
public void testCreateTripApi() throws IOException{
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>(2);
map.add("tripNme", "test trip");
org.springframework.http.HttpHeaders lhttpheader = new org.springframework.http.HttpHeaders();
lhttpheader.add("Auth-Token", "7f8b655a007dda8f93a77fcb44de3298efb67615a5585b2fdc6c95b4cc2c4a52282deae6119a2fd6c3f9b4e3723e3d1cb221376ed36d978f0ff31b585d8e70f4");
lhttpheader.setContentType(MediaType.APPLICATION_JSON);
List<HttpMessageConverter<?>> msgConverters = restTemplate.getMessageConverters();
msgConverters.add(new MappingJackson2HttpMessageConverter());
restTemplate.setMessageConverters(msgConverters);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, lhttpheader);
Response apiResponse = (Response) restTemplate.postForObject("http://localhost:8080/api/trphpr/trip/create", request, Response.class);
assertNotNull(apiResponse);
//Asserting the response of the API.
String message = apiResponse.getMessage();
Trip ltrip = (Trip)apiResponse.getValue();
assertEquals("trip created successfully", message);
assertEquals("trip test", ltrip.getTripName());
}
}
final HttpResponse response = this.call(queryUri);
entity = response.getEntity();public HttpResponse call(final URI queryUri) throws Exception
{
Future<HttpResponse> futureResponses = executor.submit(new Callable<HttpResponse>()
{
#Override
public HttpResponse call() throws Exception
{
final HttpGet httpget = new HttpGet(queryUri);
return httpclient.execute(httpget);
}
});
return futureResponses.get(A9_CALL_TIMEOUT, TimeUnit.MILLISECONDS);
}
final HttpResponse response = this.call(queryUri);
entity = response.getEntity();
parse(entity.getcontent());
wondering how do I mock all the object, can someone provide me the workable code on test class?
I would recommend that you pull out the creation of the Callable to a protected method.
public Callable<HttpResponse> createCallable(String queryUri){
return new Callable<HttpResponse>(){
#Override
public HttpResponse call() throws Exception
{
final HttpGet httpget = new HttpGet(queryUri);
return httpclient.execute(httpget);
}
});
}
I don't think you actually need EasyMock for this test. In fact it might be easier without it. In your test you can override this method to return a test stub. I think if the get times out, then it will throw a TimeoutException and not actually cancel the job. So I think you just need to catch TimeoutException to make sure everything works.
So maybe your mock just has to sleep for A9_CALL_TIMEOUT plus some additional fudge factor.
#Test
public void testTimeout(){
Subclass sut = new Subclass(){
#Override
public Callable<HttpResponse> createCallable(String queryUri){
return new Callable<HttpResponse>(){
#Override
public HttpResponse call() throws Exception{
try{
Thread.sleep(A9_CALL_TIMEOUT *2);
catch(InterruptException e) {}
}
});
};
//you can also use Junit ExpectedException rule instead
// of the try catch here
try{
sut.runQueryMethodWithExecutor();
fail("should throw timeout");
}catch(TimeoutException e){
//expected
}
}
I have a Rest Controller method using Spring 3.1 that looks like this:
#RequestMapping(value="/user", method=RequestMethod.POST, consumes={MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> addUser(#RequestBody #Valid User user){
System.out.println("called / user method");
try{
user = userService.addUser(user);
return responseBuilder.addApiResourceSucceeded(user,null);
}catch(Exception e){
return responseBuilder.apiActionFailed("user already exists", HttpStatus.CONFLICT);
}
}
I have test which looks like this:
#Before
public void setUp() {
adapter = new AnnotationMethodHandlerAdapter();
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
mapper = new ObjectMapper();
}
#Test
public void testAddUser() throws Exception {
request.setMethod("POST");
request.setContentType(MediaType.APPLICATION_JSON_VALUE);
request.setRequestURI("/user");
ObjectNode userJson = mapper.createObjectNode();
userJson.put("userId", "jonnybz");
userJson.put("email", "test#gmail.com");
userJson.put("password", "password");
userJson.put("longitude",-10.127205999);
userJson.put("latitude", 57.252269);
ArrayNode arrNode = mapper.createArrayNode();
arrNode.add(-10.1272059999);
arrNode.add(57.2522);
userJson.put("lonLat",arrNode);
request.setContent(mapper.writeValueAsBytes(userJson));
adapter.handle(request, response, userController);
String content = response.getContentAsString();
assertEquals(200, response.getStatus());
User user = dao.listAll().get(0);
objectId = user.getId();
assertNotNull(objectId);
}
When I execute a call against this endpoint from my client app (developed with angular) it works great, but when I run my test I get an " Content type 'application/json' which is coming from a HttpMediaTypeNotSupportedException" error that I cannot track down. The request never seems to hit my method. Am I missing something simple here?
Solved this problem by switching to the spring-mvc-test framework and building my test like this:
#Test
public void testAddUser() throws Exception {
ObjectNode userJson = mapper.createObjectNode();
userJson.put("userId", "jonnbz");
userJson.put("email", "test#gmail.com");
userJson.put("password", "password");
userJson.put("longitude",-10.667205999);
userJson.put("latitude", 74.252269);
ArrayNode arrNode = mapper.createArrayNode();
arrNode.add(-10.667205999);
arrNode.add(74.252269);
userJson.put("lonLat",arrNode);
MvcResult res = MockMvcBuilders.xmlConfigSetup("classpath:test-context.xml").build()
.perform(MockMvcRequestBuilders.post("/user")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.body(mapper.writeValueAsBytes(userJson)))
.andExpect(status().isOk())
.andExpect(content().type(MediaType.APPLICATION_JSON))
.andReturn();
System.out.println(res.getResponse().getContentAsString());
}
You should also include a Accept header of "application/json" in your test, since you have included a consumes="application/json", Spring MVC will match the Accept header value to the consumes value and only then call the mapped method.