1

I'm trying to write a jUnit test for a bean validation. I read How to test validation annotations of a class using JUnit? and wrote a test code like as below.

My environment:

  • Sprint Boot 2.2.6
  • Java11
  • AssertJ 3.15.0

Target Bean class:

public class Customer {

    @NotEmpty
    private String name;

    @Min(18)
    private int age;

    // getter and setter
}

JUnit test code:

public class CustomerValidationTest {
    private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    @Test
    public void test() {

        Customer customer = new Customer(null, 18);

        Set<ConstraintViolation<Customer>> violations = validator.validate(customer);
        assertThat(violations.size()).isEqualTo(1); // check violations count

        // check which constraints are violated by the message of the violation
        assertThat(violations).extracting("message").containsOnly("must not be empty");
    }
}

I'd like to check which constraints are violated. For now, I check the message of violations. Is there better way?

fanfanta
  • 181
  • 14
  • you can add a message related to field `@NotEmpty(message="name should not be empty")`, that will help you validate (using assertions) which field violated constraint. – lucid May 06 '20 at 13:43

2 Answers2

1

In your small test setup you might be able to oversee if exactly and only one violation occurs.

assertThat(violations.size()).isEqualTo(1);

and

.containsOnly("must not be empty")

However in a larger setup that might not be the case. What you actually want to do is asserting your expected violation to be present.

With the Testframework junit-jupiter-api:5.6.2 I did my test like this:

public class CustomerValidationTest {
private static Validator validator;
private static ValidatorFactory factory;

@org.junit.jupiter.api.BeforeEach
void setUp() {
    Locale.setDefault(Locale.ENGLISH);  //expecting english error messages
    factory = Validation.buildDefaultValidatorFactory();
    validator = factory.getValidator();
}

@org.junit.jupiter.api.AfterEach
void tearDown() {
    factory.close();
}

@org.junit.jupiter.api.Test
public void testContainsEmptyNameViolation() {

    Customer customer = new Customer(null, 18);

    //perform validation
    Set<ConstraintViolation<Customer>> constraintViolations = validator.validate(customer);

    boolean hasExpectedPropertyPath = constraintViolations.stream()
            .map(ConstraintViolation::getPropertyPath)
            .map(Path::toString)
            .anyMatch("name"::equals);
    boolean hasExpectedViolationMessage = constraintViolations.stream()
            .map(ConstraintViolation::getMessage)
            .anyMatch("must not be empty"::equals);

    assertAll(
            () -> assertFalse(constraintViolations.isEmpty()),
            () -> assertTrue(hasExpectedPropertyPath),
            () -> assertTrue(hasExpectedViolationMessage)
    );

Even though you asked for AssertJ, I hope that this might still be of help to you.

Simeon
  • 748
  • 1
  • 9
  • 26
0

This tutorial here shows in section 7. 'Testing .. Validations ..' a nice way of assuming that the expected violation is part of the Set.

Depending on your testing Framework this might be a strategy to follow.

@Test public void validatingObject() {
    Car car = new Car();
    Set<ConstraintViolation> violations = validator.validate(car);
    assertThat(violations.size()).isEqualTo(1);

    assertThat(violations)
      .anyMatch(havingPropertyPath("customerPropertyPathForCarViolation")
      .and(havingMessage("message of desired violation"))); }
Simeon
  • 748
  • 1
  • 9
  • 26