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