mockitoassertj

AssertJ's assertThatCode behaves differently than JUnit's assertThrows


I am having this test, junit assestion works well, while the same assertj assertion does not.

@Test
void registerWithDuplicatedEmail() throws EmailAlreadyRegistered {

    Mockito.when(customerCommand.createCustomer("Duplicated", "duplicated@mail.com", "pass"))
            .thenThrow(new EmailAlreadyRegistered());

   assertThrows(EmailAlreadyRegistered.class, () -> registerCustomerUseCase.execute("Duplicated", "duplicated@mail.com", "pass"));
   // (1) this works well

   assertThatCode(() -> registerCustomerUseCase.execute("Duplicated", "duplicated@mail.com", "pass")).hasCause(new EmailAlreadyRegistered());
   // (2) This fails with the error:
   // Expecting a cause with type: "...exception.EmailAlreadyRegistered" and message: null
   // but actualCause had no cause.

   assertThatCode(() -> registerCustomerUseCase.execute("Duplicated", "duplicated@mail.com", "pass")).doesNotThrowAnyException();
   // (3) Although it contradicts the previous one, this also fails with this error:
   // Expecting code not to raise a throwable but caught "...exception.EmailAlreadyRegistered"

   assertThatExceptionOfType(EmailAlreadyRegistered.class).isThrownBy(() -> registerCustomerUseCase.execute("Duplicated", "duplicated@mail.com", "pass"));
   // (4) This also works well

}

RegisterCustomerUseCase is pretty simple:

@Component
@RequiredArgsConstructor
public class RegisterCustomerUseCase {

    private final CustomerCommand customerCommand;

    public Customer execute(String name, String email, String password) throws EmailAlreadyRegistered {
        return customerCommand.createCustomer(name, email, password);
    }
}

Do you have any idea why cases (2) and (3) fail?


Solution

  • .hasCause checks the cause (.getCause()) of an exception, whereas assertThrows checks the exception directly. Your exception does not have a cause and thus the test fails correctly.

    You are looking for isInstanceOf with the class (not an instance) as parameter:

    assertThatCode(() -> registerCustomerUseCase.execute("Duplicated", "duplicated@mail.com", "pass"))
        .isInstanceOf(EmailAlreadyRegistered.class);
    

    Alternatively, assert with assertThatThrownBy:

    assertThatThrownBy(() -> registerCustomerUseCase.execute("Duplicated", "duplicated@mail.com", "pass"))
        .isInstanceOf(EmailAlreadyRegistered.class);