Injected authentication in RestAssuredMockMvc - java

I am writing a unit test for my controller that has an injected Authentication parameter
#RequestMapping(value = Mappings.PEOPLE, method = RequestMethod.POST)
public ResponseEntity<?> people(HttpServletRequest request, Authentication authentication, #RequestBody Person person) {
...
}
I don't know how to set the authenticaion inside of my test. Here is what I have so far.
#RunWith(SpringRunner.class)
public class PeopleTest {
#Before
public void setUp() {
RestAssuredMockMvc.standaloneSetup(new PeopleController());
}
#Test
public void testKanbanOnlyScan() {
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("username", "password"));
given()
.contentType(MediaType.APPLICATION_JSON_VALUE)
.body(new Person("Davey Jones"))
.when()
.post("/people")
.then()
.statusCode(is(HttpStatus.OK.value()));
}
}
But authentication is null in my controller during the test. How can I inject authentication into a controller?

You can use MockMVC for test your controller using something like:
#Autowired
MockMVC mockMvc;
mockMvc.perform("/your-controller-path").with(authentication(authentication))
For more details take a look in spring docs
preview-spring-security-test-web-security

You can still use RestAssuredMockMvc, if you are using the WebApplicationContext.
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class TodoControllerTest {
#Autowired
private WebApplicationContext webApplicationContext;
#BeforeEach
void init() {
RestAssuredMockMvc.webAppContextSetup(webApplicationContext);
}
#Test
void secured_api_should_react_with_default(){
given()
.when()
.get("/todo/")
.then()
.statusCode(HttpStatus.UNAUTHORIZED.value());
}
#Test
public void secured_api_should_give_http_200_when_authorized() {
given()
.auth().with(SecurityMockMvcRequestPostProcessors.httpBasic("foo", "bar"))
.when()
.get("/todo/")
.then()
.statusCode(HttpStatus.OK.value());
}
}

Related

Re-direct requests to SideEffect Utility Classes

for a spring boot application that needs to be tested below is my query.
#CustomLog
#RestController
#RequestMapping("/my_path")
public class MyController {
#GetMapping(path = "**", produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<JsonNode> fetchData(HttpServletRequest request){
... some code.....which also calls external apis.....
}
#PostMapping(path = "**", produces = {MediaType.APPLICATION_JSON_VALUE})
#ResponseBody
public ResponseEntity<Map<String, Object>> createMOI(HttpServletRequest request){
... some code.....which also calls external apis.....
}
}
My application calls an external service which now needs to be mocked.
this.webClient = WebClient.builder().baseUrl("http://localhost:9600/external_host_path")
.defaultHeader(HttpHeaders.CONTENT_TYPE,MediaType.APPLICATION_JSON_VALUE)
.build();
Mono<Pojo>responseMo = webClient.post().uri("/aGivenSubPath")
.accept(MediaType.APPLICATION_JSON).bodyValue(requestPoJo)
.retrieve().bodyToMono(Pojo.class).block();
I am calling my controller API with MVC as part of springtest
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyControllerTest {
#Autowired
MyController controller;
#Before
public void setup() throws Exception {
this.mockMvc = standaloneSetup(this.controller).build();
}
#Test
public void testControl() throws Exception {
mockMvc
.perform(post("http://localhost:9600/my_path")
.contentType(MediaType.APPLICATION_JSON)
.content("{'someData':'[]'}"))
.andExpect(status().isAccepted())
.andReturn();
}
}
What I am looking for is to somehow proxy or side effect
http://localhost:9600/external_host_path
and redirect all calls made for this host to a custom Utility class which provides response based on the request params to the external host programatically.
I have seen multiple examples for mockito, wireMock, mockwebserver, mockserver etc
But most of them work on a given(static path)-when(static path called)-then(give static response).
I have many calls through out the flow and I already have the logic of the utility class to generate responses for provided request arguments.
Although I was not able to find a answer to redirect webserver request to sideEffect class,
For now atleast managing by Mockito's MockBean and Answer.
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyControllerTest {
#Autowired
MyController controller;
#MockBean
MyExternalServiceClient serviceClient;
#Autowired
MySideEffectService sideEffect;
#Before
public void setup() throws Exception {
this.mockMvc = standaloneSetup(this.controller).build();
Mockito.when(serviceClient.getMethod(any(),anyBoolean())).thenAnswer((Answer) invocation -> {
Object[] args = invocation.getArguments();
Object mock = invocation.getMock();
return sideEffect.getMethod((Map<String, List<String>>) args[0], (Boolean) args[1]);
});
}
#Test
public void testControl() throws Exception {
mockMvc
.perform(post("http://localhost:9600/my_path")
.contentType(MediaType.APPLICATION_JSON)
.content("{'someData':'[]'}"))
.andExpect(status().isAccepted())
.andReturn();
}
}
Will still have a lookout for a way (Maybe TestContainers with image creation on the fly that will create a server with my mockCode, so that i can use hostname of this one and replace with existing real hostname)

Mockito, how to return HTTP status from void method?

I use
#ResponseStatus annotation
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
public void create(#RequestBody #Valid RestaurantCreationDTO restaurantCreationDTO,
BindingResult bindingResult) {
if(bindingResult.hasErrors()) {
throwExceptionIfBindingResultHasErrors(bindingResult);
}
restaurantService.create(restaurantCreationDTO);
}
But how can I test this method with mockito? I want to test if it's returning HttpStatus.CREATED.
You will need for example to create a #WebMvcTest that allows you to test MVC Controllers. Check the example below:
#RunWith(SpringRunner.class)
#WebMvcTest(YourRestController.class)
public class YourRestControllerTest {
#Autowired
private MockMvc mvc;
#Test
public void yourTest() throws Exception {
mvc.perform(get("/api")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isCreated());
}
}
For more details check https://www.baeldung.com/spring-boot-testing#unit-testing-with-webmvctest.

Mock Spring Controller for unit testing

I'm trying to test a rest call that is a part of an mvc controller.
My unit test is currently returning a 404 error code, instead of a 200 status code, which would determine that the request was sent successfully.
Here's the signature of my method that I'm trying to test:
#PreAuthorize("hasRole('ROLE_SSL_USER')")
#PostMapping(value = "/employee", consumes = MediaType.ALL_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
#ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<Object> postEmployee(HttpEntity<String> httpEntity, #RequestHeader("DB-Client-Id") String clientId,
#RequestHeader("X-Forwarded-Client-Dn") String dn) throws IOException, ValidationException {}
Here's my unit test class:
public class ControllerTest {
#InjectMocks
private Controller aController;
private MockMvc mockMvc;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(aController).build();
}
#Test
public void PostEmpTest() {
try {
this.mockMvc.perform(post("/employee")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Am I missing something from my perform() call that is resulting in the 404 bad request code?
I use for controller tests code like this
#RunWith(SpringRunner.class)
#WebMvcTest(Controller.class)
#AutoConfigureWebClient
public class ControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
public void entityTypes() throws Exception {
String json = "...";
mockMvc.perform(
post("URL")
.contentType(APPLICATION_JSON_UTF8)
.content(json))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_UTF8))
;
}
}
Try it - I hope, it will help.
PS: also, I'm not sure, but it looks like you need add #RequestBody to your controller method declaration:
public ResponseEntity<Object> postEmployee(
#RequestBody HttpEntity<String> httpEntity,
#RequestHeader("DB-Client-Id") String clientId,
#RequestHeader("X-Forwarded-Client-Dn") String dn) throws IOException, ValidationException {}

java.lang.AssertionError: Status expected:<200> but was:<404> in Junit test

I want to create JUnit test for Rest api and generate api doc. I want to test this code:
Rest controller
#RestController
#RequestMapping("/transactions")
public class PaymentTransactionsController {
#Autowired
private PaymentTransactionRepository transactionRepository;
#GetMapping("{id}")
public ResponseEntity<?> get(#PathVariable String id) {
return transactionRepository
.findById(Integer.parseInt(id))
.map(mapper::toDTO)
.map(ResponseEntity::ok)
.orElseGet(() -> notFound().build());
}
}
Repository interface
public interface PaymentTransactionRepository extends CrudRepository<PaymentTransactions, Integer>, JpaSpecificationExecutor<PaymentTransactions> {
Optional<PaymentTransactions> findById(Integer id);
}
I tried to implement this JUnit5 test with mockito:
#ExtendWith({ RestDocumentationExtension.class, SpringExtension.class })
#SpringBootTest(classes = PaymentTransactionsController.class)
#WebAppConfiguration
public class PaymentTransactionRepositoryIntegrationTest {
.....
private MockMvc mockMvc;
#MockBean
private PaymentTransactionRepository transactionRepository;
#BeforeEach
void setUp(WebApplicationContext webApplicationContext,
RestDocumentationContextProvider restDocumentation) {
PaymentTransactions obj = new PaymentTransactions(1);
Optional<PaymentTransactions> optional = Optional.of(obj);
PaymentTransactionRepository processor = Mockito.mock(PaymentTransactionRepository.class);
Mockito.when(processor.findById(Integer.parseInt("1"))).thenReturn(optional);
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(restDocumentation))
.alwaysDo(document("{method-name}", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())))
.build();
}
#Test
public void testNotNull() {
assertNotNull(target);
}
#Test
public void testFindByIdFound() {
Optional<PaymentTransactions> res = target.findById(Integer.parseInt("1"));
// assertTrue(res.isPresent());
}
#Test
public void indexExample() throws Exception {
this.mockMvc.perform(get("/transactions").param("id", "1"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/xml;charset=UTF-8"))
.andDo(document("index-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), links(linkWithRel("crud").description("The CRUD resource")), responseFields(subsectionWithPath("_links").description("Links to other resources")),
responseHeaders(headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`"))));
}
}
I get error:
java.lang.AssertionError: Status expected:<200> but was:<404>
What his the proper way to to make GET request to the above code?
Probably I need to add response OK when message is send back?
hi in my case i needed #MockBean of controller and all services that is was autowireing ;)
Instead of #PostMapping and #GetMapping which caused same problem while #RequestMapping in controller helped
It's a path variable, so instead of using param value, please use path variable.
For MvcResult import, you can import org.springframework.test.web.servlet
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
...
given(target.findById(anyInt())).willReturn(Optional.of(new PaymentTransactions(1))).andReturn();
MvcResult result = this.mockMvc.perform(get("/transactions/1")
.accept("application/xml;charset=UTF-8")).andReturn();
String content = result.getResponse().getContentAsString();
this.mockMvc.perform(get("/transactions/1")
.accept("application/xml;charset=UTF-8"))
.andExpect(status().isOk())
.andDo(document("index-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), links(linkWithRel("crud").description("The CRUD resource")), responseFields(subsectionWithPath("_links").description("Links to other resources")),
responseHeaders(headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`"))));
Can you try this..
public class PaymentTransactionsControllerTest {
private MockMvc mvc;
#InjectMocks
PaymentTransactionsController paymentTransactionsController;
#MockBean
private PaymentTransactionRepository processor;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.standaloneSetup(paymentTransactionsController).build();
}
#Test
public void indexExample() throws Exception {
PaymentTransactions obj = new PaymentTransactions(1);
Optional<PaymentTransactions> optional = Optional.of(obj);
Mockito.when(processor.findById(Integer.parseInt("1"))).thenReturn(optional);
MvcResult result = mvc.perform(MockMvcRequestBuilders.get("/transactions/{id}", 1))
.andDo(print())
.andExpect(status().isOk())
.andReturn();
Assert.assertNotNull(result.getResponse().getContentAsString());
}
}

RestTemplateBuilder mocked with #MockBean is null

I want to test a Tasklet implementation which uses an #Autowired RestTemplateBuilder to build a RestTemplate. The RestTemplate executes a request. I want to mock the response of this request.
#ContextConfiguration(classes = DogTasklet.class )
#RunWith(SpringRunner.class)
public class DogTaskletTest {
#MockBean
RestTemplateBuilder restTemplateBuilder;
private RestTemplate restTemplate = new RestTemplate();
#Autowired
private Tasklet sut;
#Before
public void setUp() throws Exception {
given(this.restTemplateBuilder.build()).willReturn(restTemplate);
}
}
The given() statement throws a NPE because the RestTemplateBuilder instance is null. What have I missed?
Update: I changed the test to the following which solves the NPE, now I have null ResponseEntity during sut.execute().
#RunWith(SpringRunner.class)
public class DogTaskletTest {
#TestConfiguration
static class TestConfig {
#Bean
RestTemplateBuilder restTemplateBuilder() {
RestTemplateBuilder restTemplateBuilder = mock(RestTemplateBuilder.class);
RestTemplate restTemplate = mock(RestTemplate.class);
ResponseEntity responseEntity = mock(ResponseEntity.class);
given(restTemplateBuilder.build()).willReturn(restTemplate);
given(restTemplate.execute(any(), any(), any(), any())).willReturn(responseEntity);
given(responseEntity.getBody()).willReturn("{}");
return restTemplateBuilder;
}
#Bean
DogTasklet sut() {
return new DogTasklet("string", restTemplateBuilder());
}
}
#Test
public void execute() throws Exception {
// when
sut.execute(stepContribution, chunkContext);
}
}
Thanks to Urosh I figured out that I was mocking the wrong method in my given() statement. Therefore it did not return the mocked RestTemplate.
I changed the given() to:
given(restTemplate.exchange(
anyString(),
eq(HttpMethod.GET),
any(HttpEntity.class),
eq(String.class)
)).willReturn(responseEntity);

Categories

Resources