I am currently facing an odd behavior during my test,
The goal was to test the following registration method :
@RestController
@RequiredArgsConstructor
public class RegisterController {
...
private final String secret = "";
private final String url = "https://www.google.com/recaptcha/api/siteverify";
private final UserService userService;
private final VerificationTokenService tokenService;
private final MailingService mailingService;
...
@PostMapping("/api/auth/register")
public ResponseEntity<RestUser> register(@Valid @RequestBody User user, @RequestParam("token") String token) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("secret", secret);
map.add("response", token);
// Preparing the request and extracts the response content.
RestTemplate restTemplate = new RestTemplate();
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
ResponseEntity<CaptchaResponse> response = restTemplate.postForEntity(url, request, CaptchaResponse.class);
CaptchaResponse captchaResponse = response.getBody();
// Response is 200 OK (during test).
System.out.println(response);
// The body contains CaptchaResponse (during test).
System.out.println(response.getBody());
// Always false (during test) even with mocking.
System.out.println(captchaResponse.isSuccess());
// If the captcha failed (always fails during tests).
if (captchaResponse == null || !captchaResponse.isSuccess()) return ResponseEntity.badRequest().build();
...
// Returns the programmed rest user (without the disclosure of the token) as a positive response.
return ResponseEntity.ok(u);
}
...
}
And so far the test written was :
@SpringBootTest
public class RegisterControllerTest {
private MockMvc mock;
@Autowired
private RegisterController registerController;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private UserService userService;
@MockBean
private VerificationTokenService tokenService;
@MockBean
private MailingService mailingService;
@Mock
private RestTemplate rest;
// We don't want to repeat ourselves.
private static User registeringUser;
@BeforeAll
public static void initialize() {
List<Role> defaultRoles = new ArrayList<Role>();
defaultRoles.add(new Role("USER"));
// Classic user that will attempt to register.
registeringUser = new User("test@example.com", "newenpoi", ".azerty");
registeringUser.setRoles(defaultRoles);
}
@BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
mock = MockMvcBuilders.standaloneSetup(registerController).build();
}
@Test
@DisplayName("Test registration of a lambda user for production condition with valid captcha.")
public void testRegisterProduction_shouldReturnRestUser_whenCaptchaSuccess() throws Exception {
// Given.
String token = "valid-token";
RestUser expectedRest = new RestUser(registeringUser);
VerificationToken expectedToken = new VerificationToken();
// Simulate captcha response.
CaptchaResponse captchaResponse = new CaptchaResponse();
captchaResponse.setSuccess(true);
ResponseEntity<CaptchaResponse> responseEntity = new ResponseEntity<>(captchaResponse, HttpStatus.OK);
// When.
when(rest.postForEntity(anyString(), any(HttpEntity.class), eq(CaptchaResponse.class))).thenReturn(responseEntity);
// Then.
mock.perform(post("/api/auth/register").param("token", token).contentType("application/json").content(objectMapper.writeValueAsString(registeringUser))).andExpect(status().isOk());
}
}
Whatever I attempt to do the success field from captchaResponse will always remain false, and I can't find what I am missing in my test in order to pass the if (captchaResponse == null || !captchaResponse.isSuccess())
condition!
This is the CaptchaResponse object for reference :
@RequiredArgsConstructor
@Getter
@Setter
@ToString
public class CaptchaResponse {
private boolean success;
private String challengeTs;
private String hostname;
private String[] errorcodes;
}
I did my best to follow good practices, also the debug does print a response that contains a CaptchaResponse but isSuccess() will always be false during tests and the other fiels remains null even when I explicitely set values during the test (I only kept isSuccess in the above for testing).
Ive been browsing on Stack here and there but I couldn't find unfortunately a concrete solution to this behavior.
Any help pointing me to the right direction is greatly appreciated!
You create a new instance of RestTemplate
in RegisterController
, and in the test you create a mock of RestTemplate
bean.
Try injecting a bean managed by Spring.
@RestController
@RequiredArgsConstructor
public class RegisterController {
private final RestTemplate restTemplate;