java - unit test Spring MissingServletRequestParameterException JSON response -


i have post method in spring boot rest controller follows

@requestmapping(value="/post/action/bookmark", method=requestmethod.post) public @responsebody map<string, string> bookmarkpost(         @requestparam(value="actiontype",required=true) string actiontype,         @requestparam(value="postid",required=true) string postid,         @currentuser user user) throws exception{     return service.bookmarkpost(postid, actiontype, user); } 

now if test missing parameter in postman 400 http response , json body:

{   "timestamp": "2015-07-20",   "status": 400,   "error": "bad request",   "exception": "org.springframework.web.bind.missingservletrequestparameterexception",   "message": "required string parameter 'actiontype' not present",   "path": "/post/action/bookmark" } 

until it's ok, when try unit test don't json response back

@test public void bookmarkmissingactiontypeparam() throws exception{     // @formatter:off     mockmvc.perform(                 post("/post/action/bookmark")                     .accept(mediatype.application_json)                     .param("postid", "55ab8831036437e96e8250b6")                     )             .andexpect(status().isbadrequest())             .andexpect(jsonpath("$.exception", containsstring("missingservletrequestparameterexception")));     // @formatter:on } 

the test fails , produces

java.lang.illegalargumentexception: json can not null or empty 

i did .anddo(print()) , found there no body in response

mockhttpservletresponse:           status = 400    error message = required string parameter 'actiontype' not present          headers = {x-content-type-options=[nosniff], x-xss-protection=[1; mode=block], cache-control=[no-cache, no-store], pragma=[no-cache], expires=[1], x-frame-options=[deny]}     content type = null             body =     forwarded url = null   redirected url = null          cookies = [] 

why not getting json response while unit testing controller, receive in manual testing using postman or curl?

edit: i've added @webintegrationtest got same error:

import static org.hamcrest.matchers.containsstring; import static org.springframework.test.web.servlet.request.mockmvcrequestbuilders.post; import static org.springframework.test.web.servlet.result.mockmvcresulthandlers.print; import static org.springframework.test.web.servlet.result.mockmvcresultmatchers.jsonpath; import static org.springframework.test.web.servlet.result.mockmvcresultmatchers.status; import org.junit.before; import org.junit.test; import org.junit.runner.runwith; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.beans.factory.annotation.autowired; import org.springframework.boot.test.springapplicationconfiguration; import org.springframework.boot.test.webintegrationtest; import org.springframework.http.mediatype; import org.springframework.security.web.filterchainproxy; import org.springframework.test.context.junit4.springjunit4classrunner; import org.springframework.test.web.servlet.mockmvc; import org.springframework.test.web.servlet.setup.mockmvcbuilders; import org.springframework.web.context.webapplicationcontext;  @runwith(springjunit4classrunner.class) @springapplicationconfiguration(classes = restapplication.class) @webintegrationtest public class postcontrollertest {      private mockmvc mockmvc;      @autowired     private webapplicationcontext webapplicationcontext;      @autowired     private filterchainproxy springsecurityfilterchain;      @before     public void setup() {         mockmvc = mockmvcbuilders.webappcontextsetup(webapplicationcontext)                 .addfilter(springsecurityfilterchain)                 .build();     }        @test     public void bookmarkmissingactiontypeparam() throws exception{         // @formatter:off         mockmvc.perform(                     post("/post/action/bookmark")                         .accept(mediatype.application_json)                         .param("postid", "55ab8831036437e96e8250b6")                         )                 .anddo(print())                 .andexpect(status().isbadrequest())                 .andexpect(jsonpath("$.exception", containsstring("missingservletrequestparameterexception")));         // @formatter:on     } } 

this because spring boot has auto-configured exception handler org.springframework.boot.autoconfigure.web.basicerrorcontroller not present in unit tests. way use spring boot testing support related annotations:

@springapplicationconfiguration @webintegrationtest 

more details here

update: absolutely right, behavior different in ui vs in test, error pages respond status codes not correctly hooked in non-servlet test environment. improving behavior can bug open spring mvc and/or spring boot.

for now, have workaround simulates behavior of basicerrorcontroller following way:

@runwith(springjunit4classrunner.class) @springapplicationconfiguration(classes = {restapplication.class, testconfiguration.class}) @webintegrationtest public class postcontrollertest {      private mockmvc mockmvc;      @autowired     private webapplicationcontext webapplicationcontext;      @autowired     private filterchainproxy springsecurityfilterchain;      @before     public void setup() {         mockmvc = mockmvcbuilders.webappcontextsetup(webapplicationcontext)                 .addfilter(springsecurityfilterchain)                 .build();     }        @test     public void bookmarkmissingactiontypeparam() throws exception{         // @formatter:off         mockmvc.perform(                     post("/post/action/bookmark")                         .accept(mediatype.application_json)                         .param("postid", "55ab8831036437e96e8250b6")                         )                 .anddo(print())                 .andexpect(status().isbadrequest())                 .andexpect(jsonpath("$.exception", containsstring("missingservletrequestparameterexception")));         // @formatter:on     } }      @configuration     public static class testconfiguration {           @bean         public errorcontroller errorcontroller(errorattributes errorattributes) {             return new errorcontroller(errorattributes);         }     } @controlleradvice class errorcontroller extends basicerrorcontroller {      public errorcontroller(errorattributes errorattributes) {         super(errorattributes);     }      @override     @exceptionhandler(exception.class)     @responsebody     public responseentity<map<string, object>> error(httpservletrequest request) {         return super.error(request);     } } 

what doing here adding controlleradvice handles exception flow , delegates basicerrorcontroller. atleast make behavior consistent you.


Comments

Popular posts from this blog

Fail to load namespace Spring Security http://www.springframework.org/security/tags -

sql - MySQL query optimization using coalesce -

unity3d - Unity local avoidance in user created world -