How to check JSON in response body with mockMvc - java

This is my method inside my controller which is annotated by #Controller
#RequestMapping(value = "/getServerAlertFilters/{serverName}/", produces = "application/json; charset=utf-8")
#ResponseBody
public JSONObject getServerAlertFilters(#PathVariable String serverName) {
JSONObject json = new JSONObject();
List<FilterVO> filteredAlerts = alertFilterService.getAlertFilters(serverName, "");
JSONArray jsonArray = new JSONArray();
jsonArray.addAll(filteredAlerts);
json.put(SelfServiceConstants.DATA, jsonArray);
return json;
}
I am expecting {"data":[{"useRegEx":"false","hosts":"v2v2v2"}]} as my json.
And this is my JUnit test:
#Test
public final void testAlertFilterView() {
try {
MvcResult result = this.mockMvc.perform(get("/getServerAlertFilters/v2v2v2/").session(session)
.accept("application/json"))
.andDo(print()).andReturn();
String content = result.getResponse().getContentAsString();
LOG.info(content);
} catch (Exception e) {
e.printStackTrace();
}
}
Here is the console output:
MockHttpServletResponse:
Status = 406
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Even result.getResponse().getContentAsString() is an empty string.
Can someone please suggest how to get my JSON in my JUnit test method so that I can complete my test case.

I use TestNG for my unit testing. But in Spring Test Framework they both looks similar. So I believe your test be like below
#Test
public void testAlertFilterView() throws Exception {
this.mockMvc.perform(get("/getServerAlertFilters/v2v2v2/").
.andExpect(status().isOk())
.andExpect(content().json("{'data':[{'useRegEx':'false','hosts':'v2v2v2'}]}"));
}
If you want check check json Key and value you can use jsonpath
.andExpect(jsonPath("$.yourKeyValue", is("WhatYouExpect")));
You might find thatcontent().json() are not solveble please add
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

The 406 Not Acceptable status code means that Spring couldn't convert the object to json. You can either make your controller method return a String and do return json.toString(); or configure your own HandlerMethodReturnValueHandler. Check this similar question Returning JsonObject using #ResponseBody in SpringMVC

You can try the below for get and post methods
#Autowired
private MuffinRepository muffinRepository;
#Test
public void testGetMethod throws Exception(){
Muffin muffin = new Muffin("Butterscotch");
muffin.setId(1L);
BddMockito.given(muffinRepository.findOne(1L)).
willReturn(muffin);
mockMvc.perform(MockMvcRequestBuilders.
get("/muffins/1")).
andExpect(MockMvcResutMatchers.status().isOk()).
andExpect(MockMvcResutMatchers.content().string("{\"id\":1, "flavor":"Butterscotch"}"));
}
//Test to do post operation
#Test
public void testPostMethod throws Exception(){
Muffin muffin = new Muffin("Butterscotch");
muffin.setId(1L);
BddMockito.given(muffinRepository.findOne(1L)).
willReturn(muffin);
mockMvc.perform(MockMvcRequestBuilders.
post("/muffins")
.content(convertObjectToJsonString(muffin))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResutMatchers.status().isCreated())
.andExpect(MockMvcResutMatchers.content().json(convertObjectToJsonString(muffin)));
}
If the response is empty then make sure to override equals() and hashCode() methods on the Entity your repository is working with:
//Converts Object to Json String
private String convertObjectToJsonString(Muffin muffin) throws JsonProcessingException{
ObjectWriter writer = new ObjectWriter().writer().withDefaultPrettyPrinter();
return writer.writeValueAsString(muffin);
}

There are 2 ways to check JSON responses. Lemme guide you through both of them, (taking test method from the question above, and assuming response {"data":[{"useRegEx":"false","hosts":"v2v2v2"}]} as given above)
Method 1) Asserting complete JSON
#Test
public final void testAlertFilterView() {
mockMvc.perform(get("/getServerAlertFilters/v2v2v2/")
.contentType("application/json"))
.andExpect(status().isOk())
// you may even read bigger json responses from file and convert it to string, instead of simply hardcoding it in test class
.andExpect(content().json("{"data":[{"useRegEx":"false","hosts":"v2v2v2"}]}"))
}
Method 2) Asserting specific key-value of response (not writing redundant piece of code)
.andExpect(jsonPath("$.data[0].useRegEx").value(false))
.andExpect(jsonPath("$.data[0].hosts").value("v2v2v2"));
Another thing you might need is the import statement,
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

If you want to check a few values in a specific field of JSON
.andExpect(MockMvcResultMatchers.jsonPath("$.message",
AllOf.allOf(
StringContains.containsString("name: must not be null"),
StringContains.containsString("type: must not be null")
)));
How it looks in the test class. JUnit4.
import com.fasterxml.jackson.databind.ObjectMapper;
import org.hamcrest.core.AllOf;
import org.hamcrest.core.StringContains;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.web.PageableHandlerMethodArgumentResolver;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
#RunWith(MockitoJUnitRunner.class)
public class YourControllerTest {
#Mock
private YourService service;
private MockMvc mvc;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders
.standaloneSetup(new YourController(service))
.setControllerAdvice(new YourExceptionHandler())
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build();
}
#Test
public void yourControllerMethodName_400_validation() throws Exception {
String path = "/orders/{orderId}/items";
Integer orderId = 123;
YourRequestDto requestDto = YourTestFactory.buildYourRequestDto();
requestDto.setName(null);
requestDto.setType(null);
YourResponseDto expected = YourTestFactory.buildYourResponseDto(requestDto);
Mockito
.when(service.someMethod(orderId, requestDto))
.thenReturn(expected);
mvc
.perform(
MockMvcRequestBuilders.post(path, orderId)
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(requestDto))
)
.andExpect(MockMvcResultMatchers.status().isBadRequest())
.andExpect(MockMvcResultMatchers.jsonPath("$.message",
AllOf.allOf(
StringContains.containsString("name: must not be null"),
StringContains.containsString("type: must not be null")
)));
}
}

Related

POST method test in spring. Code 400 instead of 201

I am creating an application where I can create a car object.
Car class without setters and getters:
package github.KarolXX.demo.model;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
#Entity
#Table(name = "cars")
public class Car {
#Id
#GeneratedValue(generator = "inc")
#GenericGenerator(name = "inc", strategy = "increment")
private int id;
#NotBlank(message = "car name`s must be not empty")
private String name;
private LocalDateTime productionYear;
private boolean tested;
public Car() {
}
public Car(#NotBlank(message = "car name`s must be not empty") String name, LocalDateTime productionYear) {
this.name = name;
this.productionYear = productionYear;
}
}
I would like to know how to test the POST method in Spring. Below is a code snippet for the POST method which just create Java object named Car (first snippet)
#PostMapping("/cars")
ResponseEntity<Car> createCar(#RequestBody #Valid Car newCar) {
logger.info("Creating new car");
var result = repository.save(newCar);
return ResponseEntity.created(URI.create("/" + result.getId())).body(result);
}
I am trying to test it this way:
package github.KarolXX.demo.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import github.KarolXX.demo.TestConfiguration;
import github.KarolXX.demo.model.Car;
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.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import java.time.LocalDateTime;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#SpringBootTest
#AutoConfigureMockMvc
#ActiveProfiles("integration")
class CarControllerIntegrationServerSideTest {
#Autowired
private MockMvc mockMvc;
#Test
public void httpPost_createsNewCar_returnsCreatedCar() throws Exception {
//given
Car car = new Car("second server side test", LocalDateTime.parse("2021-01-02T13:34:54"));
//when + then
mockMvc.perform(post("/cars")
.content(asJsonString(car))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isCreated());
}
public static String asJsonString(final Car objectCar) {
try {
return new ObjectMapper().writeValueAsString(objectCar);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
I did it based on this article
Unfortunately my test does not pass. Although in the logs I can see that the request body and the request headers are set correctly, I get the status 400
2021-03-26 12:05:01.532 WARN 10696 --- [ main] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Expected array or string.; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Expected array or string.
at [Source: (PushbackInputStream); line: 1, column: 59] (through reference chain: github.KarolXX.demo.model.Car["productionYear"])]
MockHttpServletRequest:
HTTP Method = POST
Request URI = /cars
Parameters = {}
Headers = [Content-Type:"application/json;charset=UTF-8", Accept:"application/json", Content-Length:"279"]
Body = {"id":0,"name":"second server side test","productionYear":{"month":"JANUARY","dayOfWeek":"SATURDAY","dayOfYear":2,"nano":0,"year":2021,"monthValue":1,"dayOfMonth":2,"hour":13,"minute":34,"second":54,"chronology":{"id":"ISO","calendarType":"iso8601"}},"tested":false,"brand":null}
Session Attrs = {}
Handler:
Type = github.KarolXX.demo.controller.CarController
Method = github.KarolXX.demo.controller.CarController#createCar(Car)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.http.converter.HttpMessageNotReadableException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 400
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
MockHttpServletRequest:
HTTP Method = POST
Request URI = /cars
Parameters = {}
Headers = [Content-Type:"application/json;charset=UTF-8", Accept:"application/json", Content-Length:"279"]
Body = {"id":0,"name":"second server side test","productionYear":{"month":"JANUARY","dayOfWeek":"SATURDAY","dayOfYear":2,"nano":0,"year":2021,"monthValue":1,"dayOfMonth":2,"hour":13,"minute":34,"second":54,"chronology":{"id":"ISO","calendarType":"iso8601"}},"tested":false,"brand":null}
Session Attrs = {}
Handler:
Type = github.KarolXX.demo.controller.CarController
Method = github.KarolXX.demo.controller.CarController#createCar(Car)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.http.converter.HttpMessageNotReadableException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 400
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Status expected:<201> but was:<400>
Expected :201
Actual :400
I have no idea what could be wrong but when I change this line of code mockMvc.perform(post("/cars") to this one mockMvc.perform(post("/") then I got status 404
I have solved the problem, but I don't know why the previous version is not working. I removed the static method from the test class and changed the POST method checking: namely I created a variable holding JSON as a String and passed it to the content method. In previous version this String was returned by ObjectMapper().writeValueAsString() in static method. My modified test class:
#Test
public void httpPost_createsNewCar_returnsCreatedCar() throws Exception {
//given
//Car car = new Car("second server side test", LocalDateTime.parse("2021-01-02T13:34:54"));
String id = String.valueOf(repo.getSize());
String jsonString = new JSONObject()
.put("id", id)
.put("tested", false)
.put("productionYear", "2017-06-18T12:12:12")
.put("name", "Toyota")
.toString();
//when + then
mockMvc.perform(post("/cars")
.content(jsonString)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isCreated());
}

How to handle `jsonParseException` from Jackson parser in Java

This is my first time writing code in Java I m running in to JsonParseException when I send invalid json data in my request body. I know I have to catch this error at the point where json body is getting parsed I don't have any idea how it works in my code. It would be great if someone can explain me how to catch the error and send the 400 response instead of the 500 which is being thrown as Uncaught server error and also how the request body is getting parsed.
I m using JAXRS: 2.0.1 and jackson for Json parsing it seems. I also added an exceptionMapper to handle these exceptions but it doesn't seem to work.
//./src/main/java/com.test.rest/Routes.java
package.com.test.rest;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
public class Routes implements Xyz{
#POST
#Path("test")
#Consumes({MediaType.APPLICATION_JSON})
#Produces(MediaType.APPLICATION_JSON)
public Response testJson(#Context HttpHeaders headers, #HeaderParam("abc") String abc, TestRequest request){
if(abc == null){
return Response.status(Response.Status.BAD_REQUEST).entity("Invalid headers").build();
}else{
return Response.status(Response.Status.OK).entity(request.gettestData()).build();
}
}
}
./src/main/java/com.test.rest/TestRequest.java
package.com.test.rest;
public class TestRequest {
private String testData;
public TestRequest () {
}
public TestRequest(String testData){
setTestData(testData);
}
public String gettestData(){
return testData;
}
public void setTestData(String testData){
if(testData!=null){
testData = testData.toLowerCase();
}
this.testData =testData;
}
}
./src/main/java/com.test.rest/JsonParseExceptionMapper.java
package.com.test.rest;
import com.fasterxml.jackson.core.JsonParseException;
import javax.annotation.Priority;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.core.*;
#Provider
#Priority(1)
public class JsonParseExceptionMapper implements ExceptionMapper<JsonParseException> {
#Override
public Response toResponse(final JsonParseException exception) {
return Response.status(Response.Status.BAD_REQUEST)
.entity("Cannot parse JSON")
.type(MediaType.TEXT_PLAIN)
.build();
}
}
All the files are in same level and I m using gradle to build my code
this is my request body
{
"testData":
}
//com.fasterxml.jackson.core.JsonParseException: Unexpected character

Rest client data into Java object. Getting com.fasterxml.jackson.databind.exc.MismatchedInputException

I have a sample backend response coming as below:
When I try to map this response into the java object, I am getting following error.
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of com.mc.membersphere.model.MemberSummaryLabel[] out of START_OBJECT token
Seems like the issue with the body tag coming from API. Which has array of objects. I need help, how to handle this body tag arrays value in Java mapping?
Backend API Response:
{
"body": [{
"pcp": "KASSAM, Far",
"er12M": "0",
"ipAdmits12M": "0",
"ipReAdmits12M": "0",
"rx12M": "0",
"pastMedicalHistory": " ",
"erCost12M": "0.0"
}
]
}
Java Program to get the Rest data into the Java objects is as below.
import java.util.Collections;
import java.util.Properties;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import com.mc.membersphere.model.MemberSummaryLabel;
import com.mc.membersphere.utility.PropertyUtil;
public class TestRestclient implements CommandLineRunner{
public static void main(String[] args) {
SpringApplication.run(TestApi.class, args); }
private static Properties prop = PropertyUtil.getProperties();
#Override
public void run(String... args) throws Exception {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
String getMVPSummaryUrl = prop.getProperty("getmvpmembersummary.url");
String url = getMVPSummaryUrl+"/"+"CA";
ResponseEntity<MemberSummaryLabel[]> response = restTemplate.exchange(url, HttpMethod.GET,entity, MemberSummaryLabel[].class);
if(response.getStatusCode()== HttpStatus.OK) {
for(MemberSummaryLabel memberSummaryLabel : response.getBody())
{
System.out.println(memberSummaryLabel.pcp);
}
//System.out.println("Print response" + response);
}
else {
System.out.println("Error");
}
}
}
MemberSummaryLabel is as below.
import com.fasterxml.jackson.annotation.JsonProperty;
public class MemberSummaryLabel {
#JsonProperty("pcp")
public String pcp;
#JsonProperty("er12M")
public Integer er12M;
#JsonProperty("ipAdmits12M")
public Integer ipAdmits12M;
#JsonProperty("ipReAdmits12M")
public Integer ipReAdmits12M;
#JsonProperty("rx12M")
public Integer rx12M;
#JsonProperty("pastMedicalHistory")
public String pastMedicalHistory;
#JsonProperty("erCost12M")
public Double erCost12M;
}
I see, its an issue with your mapping. Your response is in "body" and body contains list of MemberSummaryLabel. So, you need to have one more class as mentioned below,
public class Body{
#JsonProperty("body")
public List<MemberSummaryLabel> memberSummaryLabelList;
}
And your exchange method should return NewClass.
ResponseEntity<Body> response = restTemplate.exchange(url, HttpMethod.GET,entity, Body.class);
And for, iteration use,
for(MemberSummaryLabel memberSummaryLabel : response.getBody().getMemberSummaryLabelList()){
}

WireMock: Stubbing - Not able to implement "AssertThat" method correctly

I'm struggling to create a simple stub. I've been following the wiremock tutorial online but have had no success on the issue im facing. Particularly, the "Get" method in the AssertMethod is giving me a lot of issues. I don't know how to resolve it.
public class WeatherApplicationTest {
#Rule
public WireMockRule wireMockRule = new WireMockRule();
public WireMockServer wireMockServer = new WireMockServer(); //No-args constructor will start on port 8080, no HTTPS
#BeforeClass
public void setUpClass() {
wireMockServer.start();
}
#AfterClass
public void tearDownClass() {
wireMockServer.stop();
}
#Test
public void statusMessage() throws IOException{
wireMockRule.stubFor(get(urlEqualTo("/some/thing"))
.willReturn(aResponse()
.withStatus(200)
.withStatusMessage("Everything is fine")
.withHeader("Content-Type", "Text/Plain")));
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("http://localhost:" + wireMockServer.port() + "/some/thing");
HttpResponse response = client.execute(request);
assertThat(response.GET("/some/thing").statusCode(), is(200));
}
}
I'm getting an error on the following line:
assertThat(response.GET("/some/thing").statusCode(), is(200));
The GET method is underlined in Red.
Please Help!
The WireMock documentation doesn't do a great job of outlining how to connect with it (but, in their defense, it's not really in their slice of the pie).
As I eluded to in the comments, HttpResponse does not contain a GET() method, which is why you're getting the "red underline" (IE: error).
So we know we are looking to make an assertion against the status code. If we look at the Javadoc of the HttpResponse class, there is the StatusLine class that can be retrieved from getStatusLine() of HttpResponse, and the Javadoc of that class shows that it contains a getStatusCode() method. Combining this information into your answer, the assertion needs to be updated to:
assertThat(response.getStatusLine().getStatusCode(), is(200));
In addition, as pointed out by Tom in the comments, remove the WireMockServer (as well as the start/stop and getPort() calls; you can get the port from your rule. And the stubFor(...) method should be called statically (not as a part of the rule).
My contribution to this question: this Java test runs without exceptions, both in the IDE and in Maven as well, and, moreover with the other tests, because at the end, it shuts down the mock server, and doesn't make any conflicts with other servers running in the other tests.
import com.github.tomakehurst.wiremock.WireMockServer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import wiremock.org.apache.http.HttpResponse;
import wiremock.org.apache.http.client.HttpClient;
import wiremock.org.apache.http.client.methods.HttpGet;
import wiremock.org.apache.http.impl.client.DefaultHttpClient;
import java.io.IOException;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class KatharsisControllerTest {
private static WireMockServer mockedServer;
private static HttpClient client;
#BeforeClass
public static void setUpClass() {
mockedServer = new WireMockServer();
mockedServer.start();
client = new DefaultHttpClient();
}
#AfterClass
public static void tearDown() {
mockedServer.stop();
}
#Test
public void test_get_all_mock() {
stubFor(get(urlEqualTo("/api/Payment"))
.willReturn(aResponse()
.withHeader("Content-Type", "application/vnd.api+json;charset=UTF-8")
.withStatus(200)
.withBody("")
));
HttpGet request = new HttpGet("http://localhost:8080/api/Payment");
try {
HttpResponse response = client.execute(request);
assert response.getStatusLine().getStatusCode() == 200;
} catch (IOException e) {
e.printStackTrace();
}
}
}

Shiro: How to write a test for an endpoint protected with #RequiresRoles?

Say I have this resource:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresRoles;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
#Path("/authhello")
#Api(value = "hello", description = "Simple endpoints for testing api authentification",
hidden = true)
#Produces(MediaType.APPLICATION_JSON)
#RequiresAuthentication
public class AuthenticatedHelloWorldResource {
private static final String READ = "READ";
private static final String WRITE = "WRITE";
#GET
#ApiOperation(value = "helloworld",
notes = "Simple hello world.",
response = String.class)
#RequiresRoles(READ)
public Response helloWorld() {
String hello = "Hello world!";
return Response.status(Response.Status.OK).entity(hello).build();
}
#GET
#Path("/{param}")
#ApiOperation(value = "helloReply",
notes = "Returns Hello you! and {param}",
response = String.class)
#RequiresRoles(WRITE)
public Response getMsg(#PathParam("param") String msg) {
String output = "Hello you! " + msg;
return Response.status(Response.Status.OK).entity(output).build();
}
}
Should I write tests that confirm that certain (test) users get a response from the endpoints, and certain users don't? And if so: How can I write those tests? I've tried something like this:
import javax.ws.rs.core.Application;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.Test;
import com.cognite.api.shiro.AbstractShiroTest;
import static org.junit.Assert.assertEquals;
public class AuthenticatedHelloWorldTest extends AbstractShiroTest {
#Override
protected Application configure() {
return new ResourceConfig(AuthenticatedHelloWorldResource.class);
}
#Test
public void testAuthenticatedReadHelloWorld() {
final String hello = target("/authhello").request().get(String.class);
assertEquals("Hello world!", hello);
}
#Test
public void testAuthenticatedWriteHelloWorld() {
final String hello = target("/authhello/test").request().get(String.class);
assertEquals("Hello you! test", hello);
}
}
but I'm not sure how to actually test the function of the #RequiresRoles-annotation. I've read Shiro's page on testing, but I haven't been able to write a failing test (e.g. a test for a subject that does not have the WRITE role trying to access /authhello/test). Any tips would be appreciated.
Should I even test this?
Yes. Provided you want to make sure that certain roles will have or have not access to your resource. This will be a security integration test.
How should I go about setting up the whole application + actually call it with an http request in a test if I am to test it? Or is there a simpler way?
Part of the issue is that #RequiresAuthentication and #RequiresRoles themselves are just class and method meta information. Annotations themselves do not provide the security check functionality.
It is not clear from your question what type of container you are using but I can guess that it is plain Jersey JAX-RS service (am I right?). For Shiro to perform security checks you should have added some JAX-RS filter (maybe some other way?) around your endpoints. To test security you should replicate this setup in your tests. Otherwise there is no engine processing your annotations and no security checks as the result.

Categories

Resources