I am new to SpringBoot and it has been some time since working with SpringMVC,so likely I am missing something obvious. My test calls the controller and the controller throws an IllegalArgumentException just as I intend. However, the test does not handle it. Instead, it fails rather than passing as I would expect. Calling curl, I do see the response I expect.
My test:
#Test
void throwExceptionWhenMazeIsInvalid() {
def encodedMaze = java.net.URLEncoder.encode("""#
##########
""", "UTF-8")
mvc.perform(MockMvcRequestBuilders.get("/solve?maze=${encodedMaze}").accept(MediaType.APPLICATION_JSON))
.andExpect(status().is(500))
// .andDo(MockMvcResultHandlers.print())
.andExpect(content().string("The maze is improperly formatted."))
.andDo(print())
// .andReturn()
}
My method under test:
#RestController
class MazeController {
#RequestMapping(value = "/solve", method = RequestMethod.GET, produces = "application/json")
String solve(#RequestParam("maze") String layout){
println "MazeController.solve(${layout})"
String decoded = java.net.URLDecoder.decode(layout, "UTF-8")
if (!MazeValidator.isValid(decoded)) {
throw new IllegalArgumentException("The maze is improperly formatted.")
}
String expectedMaze = """##########
#A##.#...#
#.####.#.#
#.####.#.#
#.######B#
#.#.######
#....#####
##########
"""
JsonBuilder json = new JsonBuilder()
// json { message decoded }
json { message expectedMaze }
println "============= RETURNING response"
return json.toString()
}
}
My curl:
> curl localhost:8080/solve
{"timestamp":"2018-10-24T21:45:19.025+0000","status":500,"error":"Internal Server Error","message":"The maze is improperly formatted.","path":"/solve"}
Have you tried setHandlerExceptionResolvers for your mocked mvc?
Related
I am new to testing and i am trying to write a unit test cases on a Flink Datastream which takes input a jsonobject and passes the json object to a processfuntion and it returns a valid or invalid jsonobject when certain rule conditions are met below is the junit test case, below i am trying to compare the output jsonobject from process function with the jsonobject of the input file
#Test
public void testcompareInputAndOutputDataJSONSignal() throws Exception {
org.json.JSONObject jsonObject = toJsonObject();
String input = jsonObject.toString();
String output = JSONDataStreamOutput();
assertEquals(mapper.readTree(input), mapper.readTree(output));
}
below is my toJSONObject and JSONDataStream meathods
public static JSONObject toJsonObject() throws IOException, ParseException {
JSONParser jsonParser = new JSONParser();
FileReader fileReader = new FileReader(getFileFromResources("input.json"));
JSONObject obj = (JSONObject) jsonParser.parse(fileReader);
return obj;
}
public String SignalDataStreamOutput() throws Exception {
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<JSONObject> validSignal = env.fromElements(toJsonObject())
.process(new JsonFilter());
String outputFolder = "output";
validSignal.writeAsText(outputFolder).setParallelism(1);
env.execute();
String content = new String(Files.readAllBytes(Paths.get("output.txt")));
return content;
}
What i am doing is i am converting a jsonfile to jsonobject using the toJSONObject method and sending to a data stream using SignalDataStreamOutput method which will intern send it to a process function in JsonFilter class and validate it against a set of rules and if it's valid it will return a jsonobject and when trying to access the jsonobject directly from stream i am getting value like org.apache.flink#994jdkeiri so i am trying to write the output to a file and trying to read it back to a string and comparing it in test method but this is a work around process and i found a link to use Mockito framework here i changed it to use json object like below
final Collector<JSONObject> collectorMock = (Collector<JSONObject>)Mockito.mock(JsonFilter.class);
final Context contextMock = Mockito.mock(Context.class);
#Test
public void testcompareInputAndOutputDataForValidSignal() throws Exception {
org.json.JSONObject jsonObject = convertToJsonObject();
Mockito.verify(collectorMock).collect(jsonObject);
}
but the above approach is also not working can you suggest me simplified approach to test the json object
Written my Junit test case as below. Getting some no such method error when i run my testcases.
ResponseObject res = initialized with some data;
ServiceImpl servie;
#Test
public void methidName(){
ResponseObject mockObject= Mockito.spy(new ResponseObject(data));
mockObject.setters() // more setters follows
doReturn(someretunObject).when(mockObject).somethod();
// calling actual method here now
service.transfor();
}
Actual Classes
ResponseOject {
List<JSONObject> jsonList;
......
}
ServiceImpl{
public SearchResponse transfor(SearchResponse response) {
JSONObject obj= new JSONObject(response.getConent());
JSONArray arr= (JSONArray) obj.get("RootNode");
ArrayList<JSONObject> list=new ArrayList<>();
for(int i=0i<arr.size();i++){
list.add(arr.get(i));
}
// doing some sorting here with the list
Collections.sort(list, comparator);
/**/ setting the sorted collection to response object as below**
response.setJsonList(list);
JSONObject obj= new JSONObject();
obj.put("rootNode", response.getJsonList);
// getting error in above line during Junit testcase run
}
}
Problem Statement
Getting error at this point in actual method
obj.put("rootNode", response.getJsonList);
java.lang.NoSuchMethodError: org.json.JSONObject.put(Llava/lang/String;Ljava/lanf/
Collection;)Lorg/json/JSONObject
Any reason why it so. Am i missing something?
Are you calling the method you think you are? Your test is invoking this method:
service.transfor()
but your code example shows this method:
public SearchResponse transfor(SearchResponse response)
The one you showed takes an input parameter, but you aren't passing one, so it appears you are not invoking the method you intend to be testing. If this is just a mistake in what you posted, then you should look at what object you have mocked to be returned by the response.getJsonList call. If it is returning an object that is of a type that is different from the type required by the obj.put method then you could get this error.
I am new to this #ExceptionHandler. I need to return response in JSON format if there is any exception. My code is returning response in JSON format if the operation is successful. But when any exception is thrown it is return HTML response as I have used #ExceptionHandler.
Value and reason in #ResponseStatus is coming properly but in HTML. How can I can change it to a JSON response? Please help.
In my controller class i have this methods:
#RequestMapping(value = "/savePoints", method = RequestMethod.POST, consumes = "application/json", produces = "application/json;charset=UTF-8")
public #ResponseBody
GenericResponseVO<TestResponseVO> saveScore(
#RequestBody(required = true) GenericRequestVO<TestVO> testVO) {
UserContext userCtx = new UserContext();
userCtx.setAppId("appId");
return gameHandler.handle(userCtx, testVO);
}
Exception handling method:
#ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Error in the process")
#ExceptionHandler(Exception.class)
public void handleAllOtherException() {
}
You can annotate the handler method with #ResponseBody and return any object you want and it should be serialized to JSON (depending on your configuration of course). For instance:
public class Error {
private String message;
// Constructors, getters, setters, other properties ...
}
#ResponseBody
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ExceptionHandler(MethodArgumentNotValidException.class)
public Error handleValidationException(MethodArgumentNotValidException e) {
// Optionally do additional things with the exception, for example map
// individual field errors (from e.getBindingResult()) to the Error object
return new Error("Invalid data");
}
which should produce response with HTTP 400 code and following body:
{
"message": "Invalid data"
}
Also see Spring JavaDoc for #ExceptionHandler which lists possible return types, one of which is:
#ResponseBody annotated methods (Servlet-only) to set the response content. The return value will be converted to the response stream using message converters.
Replace
#ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Error in the process")
by
#ResponseStatus(value = HttpStatus.NOT_FOUND)
the 'reason' attribute force html render!
I've waste 1 day on that.....
I have implemented a simple controller with a simple request / response.
Controller
#RestController
#RequestMapping("/")
public class HelloWorldController extends AbstractRestController {
#RequestMapping(value = "/hello", method = RequestMethod.POST)
public HelloWorldResponse sayHello(#Valid #RequestBody HelloWorldRequest request) {
String message = String.format("Hello %s!", request.getSayHelloTo());
return new HelloWorldResponse(message);
}
}
Request
public class HelloWorldRequest {
#NotEmpty
#NotNull
private String sayHelloTo;
protected HelloWorldRequest() {
}
public HelloWorldRequest(String sayHelloTo) {
this.sayHelloTo = sayHelloTo;
}
public String getSayHelloTo() {
return sayHelloTo;
}
#Override
public String toString() {
return "HelloWorldRequest{" +
"sayHelloTo='" + sayHelloTo + '\'' +
'}';
}
}
When i want to test the correct output for the default error handling i seem to be unable to check the output of the default json format using a unit test. The response always seems to be empty. When i fire the request via a normal curl command is see a correct response. I assume this is because the returned JSON cannot be mapped on the HelloWorldResponse. Is there any way of checking if the returned output is valid on the response body?
Test
class TestSpec extends Specification {
MockMvc mockMvc
def setup() {
mockMvc = MockMvcBuilders.standaloneSetup(new HelloWorldController()).build()
}
def "Test simple action"() {
when:
def response = mockMvc.perform(post("/hello")
.contentType(MediaType.APPLICATION_JSON)
.content('{"sayHelloTo": ""}')
)
then:
response.andExpect(status().isOk())
}
}
Json Response
{
"timestamp" : 1426615606,
"exception" : "org.springframework.web.bind.MissingServletRequestParameterException",
"status" : 400,
"error" : "Bad Request",
"path" : "/welcome",
"message" : "Required String parameter 'name' is not present"
}
try to debug with print() method, may be exception is thrown during execution.
MvcResult andReturn = mockMvc.perform(get("/api")
.accept(MediaType.APPLICATION_JSON))
.andDo(print())
.andReturn();
The #Controller class you posted and the Test case (and response) don't seem to match (you're calling /hello in your test case and your #RequestMapping says /welcome ... Can we see the correct code? It looks like you have a #RequestParam("name") set, but you're not passing it.
I have created a rest webservice which has a below code in one method:
#POST
#Path("/validUser")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public JSONObject validUserLogin(#QueryParam(value="userDetails") String userDetails){
JSONObject json = null;
try{
System.out.println("Service running from validUserLogin :"+userDetails);
json = new JSONObject(userDetails);
System.err.println("UserName : "+json.getString("userName")+" password : "+json.getString("password"));
json.put("httpStatus","OK");
return json;
}
catch(JSONException jsonException) {
return json;
}
}
I am using Apache API in the client code.And below client code is calling this service, by posting some user related data to this service:
public static String getUserAvailability(String userName){
JSONObject json=new JSONObject();
try{
HttpContext context = new BasicHttpContext();
HttpClient client = new DefaultHttpClient();
client.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2109);
URI uri=new URIBuilder(BASE_URI+PATH_VALID_USER).build();
HttpPost request = new HttpPost(uri);
request.setHeader("Content-Type", "application/json");
json.put("userName", userName);
StringEntity stringEntity = new StringEntity(json.toString());
request.setEntity(stringEntity);
HttpResponse response = client.execute(request,context);
System.err.println("content type : \n"+EntityUtils.toString(response.getEntity()));
}catch(Exception exception){
System.err.println("Client Exception: \n"+exception.getStackTrace());
}
return "OK";
}
The problem is, I am able to call the service, but the parameter I passed in the request to service results in null.
Am I posting the data in a wrong way in the request. Also I want to return some JSON data in the response, but I am not able to get this.
With the help of Zack , some how i was able to resolve the problem,
I used jackson-core jar and changed the service code as below.
#POST
#Path("/validUser")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public JSONObject validUserLogin(String userDetails){
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readValue(userDetails, JsonNode.class);
System.out.println("Service running from validUserLogin :"+userDetails);
System.out.println(node.get("userName").getTextValue());
//node.("httpStatus","OK");
return Response.ok(true).build();
}