java - Inject @AuthenticationPrincipal when unit testing a Spring REST controller -
i having trouble trying test rest endpoint receives userdetails
parameter annotated @authenticationprincipal
.
seems user instance created in test scenario not being used, attempt instantiate using default constructor made instead: org.springframework.beans.beaninstantiationexception: failed instantiate [com.andrucz.app.appuserdetails]: no default constructor found;
rest endpoint:
@restcontroller @requestmapping("/api/items") class itemendpoint { @autowired private itemservice itemservice; @requestmapping(path = "/{id}", method = requestmethod.get, produces = mediatype.application_json_utf8_value) public callable<itemdto> getitembyid(@pathvariable("id") string id, @authenticationprincipal appuserdetails userdetails) { return () -> { item item = itemservice.getitembyid(id).orelsethrow(() -> new resourcenotfoundexception(id)); ... }; } }
test class:
public class itemendpointtests { @injectmocks private itemendpoint itemendpoint; @mock private itemservice itemservice; private mockmvc mockmvc; @before public void setup() { mockitoannotations.initmocks(this); mockmvc = mockmvcbuilders.standalonesetup(itemendpoint) .build(); } @test public void finditem() throws exception { when(itemservice.getitembyid("1")).thenreturn(optional.of(new item())); mockmvc.perform(get("/api/items/1").with(user(new appuserdetails(new user())))) .andexpect(status().isok()); } }
how can solve problem without having switch webappcontextsetup
? write tests having total control of service mocks, using standalonesetup
.
for reason michael piefel's solution didn't work me came one.
first of all, create abstract configuration class:
@runwith(springrunner.class) @springboottest @testexecutionlisteners({ dependencyinjectiontestexecutionlistener.class, dirtiescontexttestexecutionlistener.class, withsecuritycontexttestexecutionlistener.class}) public abstract mockmvctestprototype { @autowired protected webapplicationcontext context; protected mockmvc mockmvc; protected org.springframework.security.core.userdetails.user loggeduser; @before public voivd setup() { mockmvc = mockmvcbuilders .webappcontextsetup(context) .apply(springsecurity()) .build(); loggeduser = (user) securitycontextholder.getcontext().getauthentication().getprincipal(); } }
then can write tests this:
public class sometestclass extends mockmvctestprototype { @test @withuserdetails("someuser@app.com") public void sometest() throws exception { mockmvc. perform(get("/api/someservice") .withuser(user(loggeduser))) .andexpect(status().isok()); } }
and @authenticationprincipal should inject own user class implementation controller method
public class somecontroller { ... @requestmapping(method = post, value = "/update") public string update(udatedto dto, @authenticationprincipal currentuser user) { ... user.getuser(); // works charm! ... } }
Comments
Post a Comment