AssertJ custom assertion for testing ConstraintValidator implementations

Posted at — Apr 1, 2016
Riekpil logo
Learn how to test real-world applications with the Testing Spring Boot Applications Masterclass. Comprehensive online course with 8 modules and 130+ video lessons to master well-known Java testing libraries: JUnit 5, Mockito, Testcontainers, WireMock, Awaitility, Selenium, LocalStack, Selenide, and Spring's Outstanding Test Support.

If you want to unit test a ConstraintValidator with AssertJ, then you can use this custom validator to make the tests more readable:

import org.assertj.core.api.AbstractAssert;

import javax.validation.ConstraintViolation;
import java.util.Set;
import java.util.stream.Collectors;

public class ConstraintViolationSetAssert extends AbstractAssert<ConstraintViolationSetAssert, Set<? extends ConstraintViolation>> {

    public ConstraintViolationSetAssert(Set<? extends ConstraintViolation> actual) {
        super(actual, ConstraintViolationSetAssert.class);
    }

    public static ConstraintViolationSetAssert assertThat(Set<? extends ConstraintViolation> actual) {
        return new ConstraintViolationSetAssert(actual);
    }

    public ConstraintViolationSetAssert hasViolationOnPath(String path) {
        isNotNull();

        // check condition
        if (!containsViolationWithPath(actual, path)) {
            failWithMessage("There was no violation with path <%s>. Violation paths: <%s>", path, actual.stream()
                                                                                                        .map(violation -> violation
                                                                                                                .getPropertyPath()
                                                                                                                .toString())
                                                                                                        .collect(
                                                                                                                Collectors
                                                                                                                        .toList()));
        }

        return this;
    }

    private boolean containsViolationWithPath(Set<? extends ConstraintViolation> violations, String path) {
        boolean result = false;

        for (ConstraintViolation violation : violations) {
            if (violation.getPropertyPath().toString().equals(path)) {
                result = true;
                break;
            }
        }
        return result;
    }
}

An example unit test that uses this:

@Test
public void givenInvalidUsername_violationConstraint() {
    CreateUserParameters p = new CreateUserParameters();
    p.setUsername("x");

    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    Validator validator = factory.getValidator();

    Set<ConstraintViolation<CreateUserParameters>> violationSet = validator.validate(parameters);

    // static import for ConstraintViolationSetAssert
    assertThat(violationSet).hasViolationOnPath("username");
}

See http://joel-costigliola.github.io/assertj/assertj-core-custom-assertions.html for the documentation if you want to create your own custom assertions using AssertJ. There is even a Maven plugin that allows to generate custom assertions automatically: http://joel-costigliola.github.io/assertj/assertj-assertions-generator-maven-plugin.html

If you want to be notified in the future about new articles, as well as other interesting things I'm working on, join my mailing list!
I send emails quite infrequently, and will never share your email address with anyone else.