java - Autowired HttpServletRequest in Spring-test integration tests -


i trying test cover login functionality. version of spring 3.2.12. have session bean, declared as:

@service @scope(value = "session", proxymode = scopedproxymode.interfaces) public class clientsessionserviceimpl implements clientsessionservice {     @autowired     private httpservletrequest request;     // method called during login routine filter     public boolean checkuser() {     // rely on request attributes here, set in filter     } 

this works when run on server, when run means of spring-test, problem comes. test method:

this.mockmvc = mockmvcbuilders.webappcontextsetup(this.wac).addfilter(springsecurityfilterchain).build(); mockmvc.perform(post(url)); 

after debugging, found out, when test spring context started, in servlettestexecutionlistener.setuprequestcontextifnecessary instance of mockhttpservletrequest created, mockhttpservletrequest request = new mockhttpservletrequest(mockservletcontext);
 // lets' call instance a. , instance that's injected everywhere, use

@autowired httpservletrequest request; 

whereas, calling mockmvc.perform, creates instance of mockhttpservletrequest (let's call instance b), passed filters, servlets, etc. so, basically, attribute set in filter in request, can't read in clientsessionserviceimpl, because different instance of mockhttpservletrequest injected there.

i spent bunch of time on this, still have not found solution.

p.s. searched through stackoverflow, there questions similar titles, describing problems differ mine, don't want pass httpservletrequest parameter, , prefer have autowired, unless there reason it.

so, basically, attribute set in filter in request, can't read in clientsessionserviceimpl, because different instance of mockhttpservletrequest injected there.

this timing issue regard when spring's requestattributes populated in requestcontextholder. in production assume configuring either requestcontextfilter or requestcontextlistener.

in case, manually adding instance of requestcontextfilter front of filter chain in test solve problem.

mockmvc = mockmvcbuilders   .webappcontextsetup(this.wac)   .addfilters(new requestcontextfilter(), testfilterchain)   .build(); 

please note become default behavior in spring framework 4.2: code simulates requestcontextfilter implemented directly in mockmvc. see jira issue spr-13217 details.


as aside, configuring mockhttpservletrequest created servlettestexecutionlistener not supported. if using mockmvc expected configure mocked request via requestbuilders.

however, having said that, if have concrete need modifying mock request created servlettestexecutionlistener manually , having re-used mockmvc, can create following class in project:

package org.springframework.test.web.servlet.request;  import javax.servlet.servletcontext; import javax.servlet.http.httpservletrequest;  import org.springframework.http.httpmethod; import org.springframework.mock.web.mockhttpservletrequest; import org.springframework.web.context.request.requestattributes; import org.springframework.web.context.request.requestcontextholder; import org.springframework.web.context.request.servletrequestattributes;  /**  * patched version of {@link mockhttpservletrequestbuilder}.  *  * @author sam brannen  * @since 4.2  */ public class patchedmockhttpservletrequestbuilder extends mockhttpservletrequestbuilder {      public static mockhttpservletrequestbuilder get(string urltemplate, object... urlvariables) {         return new patchedmockhttpservletrequestbuilder(httpmethod.get, urltemplate, urlvariables);     }      public patchedmockhttpservletrequestbuilder(httpmethod httpmethod, string urltemplate, object... urlvariables) {         super(httpmethod, urltemplate, urlvariables);     }      /**      * create {@link mockhttpservletrequest}.      * <p>if instance of {@code mockhttpservletrequest} available via      * {@link requestattributes} bound current thread in      * {@link requestcontextholder}, method returns instance.      * <p>otherwise, method creates new {@code mockhttpservletrequest}      * based on supplied {@link servletcontext}.      * <p>can overridden in subclasses.      * @see requestcontextholder#getrequestattributes()      * @see servletrequestattributes      */     @override     protected mockhttpservletrequest createservletrequest(servletcontext servletcontext) {         requestattributes requestattributes = requestcontextholder.getrequestattributes();         if (requestattributes instanceof servletrequestattributes) {             httpservletrequest request = ((servletrequestattributes) requestattributes).getrequest();             if (request instanceof mockhttpservletrequest) {                 return (mockhttpservletrequest) request;             }         }          return new mockhttpservletrequest(servletcontext);     }  } 

note: must in org.springframework.test.web.servlet.request package; otherwise, can't extend mockhttpservletrequestbuilder required.

then, use get() method patchedmockhttpservletrequestbuilder instead of mockmvcrequestbuilders, , should work expect!

obviously, above example re-implements get(), can naturally same post(), etc.

fyi: might commit above patched version of createservletrequest() spring framework 4.2.x (see jira issue spr-13211).

regards,

sam (author of spring testcontext framework)


Comments

Popular posts from this blog

javascript - oscilloscope of speaker input stops rendering after a few seconds -

javascript - gulp-nodemon - nodejs restart after file change - Error: listen EADDRINUSE events.js:85 -

Fatal Python error: Py_Initialize: unable to load the file system codec. ImportError: No module named 'encodings' -