I am trying to write unit test cases for Mycontroller using WebTestClient in my web-flux Spring boot application.
It is always returning 401 while try to execute my unit test case. I already go through some old answers of stackoverflow but no luck.
Below are the approaches that I followed till now:
Disable security using @WebFluxTest(controllers = MyController.class,excludeAutoConfiguration = {ReactiveSecurityAutoConfiguration.class}))
Above one disabled security perfecty but the issue is I am getting java.security.Principal null in MyController and controller throwing null pointer exception while trying to fetch value from Principal.
Add default bearer token in my webTestClient test. In this case I am getting 401.
Add valid bearer token in WebTestClient test that we are using to hit APIs normally. It this case as well I am getting 401[unauthorized] error.
Tried to mock Principal object but didn't got success. below is the code that I tried:
Authentication authentication = Mockito.mock(Authentication.class); SecurityContext securityContext = Mockito.mock(SecurityContext.class); Mockito.when(securityContext.getAuthentication()).thenReturn(authentication); SecurityContextHolder.setContext(securityContext); SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL); SecurityContextHolder.getContext().setAuthentication(authentication); Collection<GrantedAuthority> authorities = new ArrayList<>(); UsernamePasswordAuthenticationToken principal1 = new UsernamePasswordAuthenticationToken("testUser", "testPass"); Mockito.when(authentication.getPrincipal()).thenReturn(principal1);
Below is MyController and MyControllerTest class for your reference:
MyColroller.java
@GetMapping(produces = APPLICATION_JSON_VALUE, value = "/myController/{transactionId}") @Operation( security = @SecurityRequirement(name = OAUTH2), responses = { @ApiResponse(responseCode = "200", content = @Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = TransactionDocumentResponse.class))) }) public ResponseEntity<TransactionDocumentResponse> get( @PathVariable(value = "transactionId") String transactionId, Principal principal) { Map<String, String> userInfo = (Map) ((Authentication) principal).getDetails(); utility.checkForMissingToken(userInfo, xTestHeader); return service.get(transactionId, userInfo); }
MyControllerTest.java
@RunWith(SpringRunner.class) @WebFluxTest(controllers = {MyController.class}) @AutoConfigureWebTestClient @TestPropertySource( properties = { "default-jwt-token = my default jwt token", } ) public class MyControllerTests { private static final String testTransactionId = "abc_def"; private static final BigInteger testTransactionIdBigInteger = BigInteger.valueOf(123); @Value("${default-jwt-token}") private String jwtToken; @MockBean MyServiceImpl service; @MockBean Utility utility; @Autowired private WebTestClient webTestClient; @Test public void test_success() { TransactionDocumentResponse transactionDocumentResponse = new TransactionDocumentResponse(); transactionDocumentResponse.setTransactionId(testTransactionIdBigInteger); ResponseEntity<TransactionDocumentResponse> response = ResponseEntity.of(Optional.of(transactionDocumentResponse)); Mockito.doNothing().when(utility).checkForMissingToken(anyMap(), anyString()); when(service.getRevolvingTransactions(anyString(), anyMap())).thenAnswer(createAnswer(response)); WebTestClient.BodySpec<JSONObject, ?> stringBodySpec = webTestClient .method(HttpMethod.GET) .uri("/myController/{transactionId}", testTransactionId) .headers(h -> { h.setBearerAuth(jwtToken); }) .exchange() .expectBody(JSONObject.class); assertEquals(123, stringBodySpec.returnResult().getResponseBody().get("transactionId")); } }
Basically I need some mechanism to mock Spring security so that 401 error gone and I got some value in my Principal object.
Also I already tried older solutions so please don't mark it duplicate :).
Thanks