I'm writing a test case to verify that an EmailSendingException
results in an HTTP 500 response. However, when the exception is thrown, my test still returns a status of 200 instead of the expected 500.
Here are the relevant parts of my code:
Test Case:
@Test
@WithMockUser(username = "admin", roles = {"ADMIN"})
void testSendBasicEmail_Failure() throws Exception {
// Arrange
BasicEmailRequest request = new BasicEmailRequest();
request.setToEmail("test@example.com");
request.setSubject("Test Subject");
request.setBody("Test Body");
request.setIsHtml(false);
doThrow(new EmailSendingException("Failed to send email")).when(emailOperations)
.sendBasicEmail(anyString(), anyList(), anyList(), anyString(), anyString(), anyBoolean());
// Act & Assert
mockMvc.perform(post("/api/email/sendBasic")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isInternalServerError()) // Expecting HTTP 500
.andExpect(content().string("Failed to send email. Please try again later."));
verify(emailOperations, times(1)).sendBasicEmail(
"test@example.com", null, null, "Test Subject", "Test Body", false);
}
Controller:
@PostMapping("/sendBasic")
@PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
public ResponseEntity<String> sendBasicEmail(@Valid @RequestBody BasicEmailRequest request) throws EmailSendingException {
logger.info("Sending basic email: {}", request);
emailOperations.sendBasicEmail(
request.getToEmail(),
request.getCcEmails(),
request.getBccEmails(),
request.getSubject(),
request.getBody(),
request.getIsHtml()
);
return ResponseEntity.ok("Email sent successfully.");
}
Exception Handling:
@ExceptionHandler(EmailSendingException.class)
public ResponseEntity<ErrorResponse> handleEmailSendingException(EmailSendingException ex) {
logger.error("Email sending failed: {}", ex.getMessage(), ex);
ErrorResponse errorResponse = new ErrorResponse("EMAIL_SENDING_FAILED", ex.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
}
The test fails with the following error message:
java.lang.AssertionError: Status expected:<500> but was:<200>
Expected :500
Actual :200
I expect an HTTP 500 status when the EmailSendingException
is thrown, but instead, I'm getting an HTTP 200 response with "Email sent successfully." What could be causing this, and how can I fix it?
Environment:
Spring Boot: 3.3.4
Spring Security
Spring Test
JUnit 5
Mockito
Any advice on how to resolve this would be appreciated!
In your test, your ccEmails
and bccEmails
fields are null
. However, ArgumentMatchers.anyList()
does only match non-null lists, as mentioned by the API docs:
Any non-null
List
.Since Mockito 2.1.0, only allow non-null
List
. As this is a nullable reference, the suggested API to matchnull
wrapper would beisNull()
. We felt this change would make test harnesses much safer than they were with Mockito 1.x.
The result is that your exception is never thrown by the mock because it doesn't match.
So as mentioned by the API docs, you could use isNull()
. Alternatively, you could use any()
:
doThrow(new EmailSendingException("Failed to send email"))
.when(emailOperations)
.sendBasicEmail(
anyString(),
isNull(), // Change this
isNull(), // Change this
anyString(),
anyString(),
anyBoolean());
My personal opinion is that since you already have a verify()
statement confirming the exact call, I prefer using any()
everywhere in the doThrow()
statement. If you use the wrong matcher, you can detect it far easier with the verify()
API than with when()
.