All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kiwiproject.test.validation.ValidationTestHelper Maven / Gradle / Ivy

There is a newer version: 3.7.0
Show newest version
package org.kiwiproject.test.validation;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.kiwiproject.collect.KiwiLists.isNotNullOrEmpty;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import lombok.experimental.UtilityClass;
import org.assertj.core.api.SoftAssertions;
import org.kiwiproject.base.KiwiStrings;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * Provides helper methods for making assertions on validation of objects using the Bean Validation API.
 * 

* NOTE: Most validation assertions methods have a vararg parameter to allow specification of the group(s) * targeted for validation. The only ones that currently do NOT have group support are the methods that * already have a vararg to check the actual validation messages. At the present time, we have decided not * to add group support as these methods have generally been used much less often. */ @UtilityClass public class ValidationTestHelper { private static final Validator VALIDATOR = newValidator(); /** * Returns a singleton {@link Validator} instance. * * @return a singleton {@link Validator} instance */ public static Validator getValidator() { return VALIDATOR; } /** * Creates a new, default {@link Validator} instance using the default validator factory provided by the underlying * bean validation implementation, for example the reference implementation Hibernate Validator. * * @return a new {@link Validator} instance */ public static Validator newValidator() { // noinspection resource return Validation.buildDefaultValidatorFactory().getValidator(); } /** * Asserts that there are no constraint violations on the given object using a * default validator. * * @param object the object to validate * @param groups the optional validation groups to apply */ public static void assertNoViolations(Object object, Class... groups) { assertNoViolations(VALIDATOR, object, groups); } /** * Asserts that there are no constraint violations on the given object using the * specified validator. * * @param validator the Validator instance to perform validation with * @param object the object to validate * @param groups the optional validation groups to apply */ public static void assertNoViolations(Validator validator, Object object, Class... groups) { var violations = validator.validate(object, groups); assertThat(violations).isEmpty(); } /** * Performs an AssertJ soft assertion that there are no constraint violations on the given * object using a default validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may not be empty. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param object the object to validate * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects that were found when validating the object */ public static Set> assertNoViolations(SoftAssertions softly, T object, Class... groups) { return assertNoViolations(softly, VALIDATOR, object, groups); } /** * Performs an AssertJ soft assertion that there are no constraint violations on the given * object using the specified validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may not be empty. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param validator the Validator instance to perform validation with * @param object the object to validate * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects that were found when validating the object */ public static Set> assertNoViolations(SoftAssertions softly, Validator validator, T object, Class... groups) { var violations = validator.validate(object, groups); softly.assertThat(violations).isEmpty(); return violations; } /** * Asserts that there is at least one constraint violation on the given object using a default validator. * * @param object the object to validate * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects, when the assertion passes */ public static Set> assertHasViolations(T object, Class... groups) { return assertHasViolations(VALIDATOR, object, groups); } /** * Asserts that there is at least one constraint violation on the given object using the given validator. * * @param validator the Validator instance to perform validation with * @param object the object to validate * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects, when the assertion passes */ public static Set> assertHasViolations(Validator validator, T object, Class... groups) { var violations = validator.validate(object, groups); assertThat(violations) .describedAs("Expected at least one constraint violation") .isNotEmpty(); return violations; } /** * Performs an AssertJ soft assertion that is at least one constraint violation * on the given object using a default validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may or may not have the expected values. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param object the object to validate * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects that were found when validating the object */ public static Set> assertHasViolations(SoftAssertions softly, T object, Class... groups) { return assertHasViolations(softly, VALIDATOR, object, groups); } /** * Performs an AssertJ soft assertion that is at least one constraint violation * on the given object using the given validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may or may not have the expected values. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param validator the Validator instance to perform validation with * @param object the object to validate * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects that were found when validating the object */ public static Set> assertHasViolations(SoftAssertions softly, Validator validator, T object, Class... groups) { var violations = validator.validate(object, groups); softly.assertThat(violations) .describedAs("Expected at least one constraint violation") .isNotEmpty(); return violations; } /** * Asserts that there are exactly {@code numExpectedViolations} constraint violations on the given object * using a default validator. * * @param object the object to validate * @param numExpectedViolations the number of violations that are expected * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects, when the assertion passes */ public static Set> assertViolations(T object, int numExpectedViolations, Class... groups) { return assertViolations(VALIDATOR, object, numExpectedViolations, groups); } /** * Asserts that there are exactly {@code numExpectedViolations} constraint violations on the given object * using the specified validator. * * @param validator the Validator instance to perform validation with * @param object the object to validate * @param numExpectedViolations the number of violations that are expected * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects, when the assertion passes */ public static Set> assertViolations(Validator validator, T object, int numExpectedViolations, Class... groups) { var violations = validator.validate(object, groups); assertThat(violations).hasSize(numExpectedViolations); return violations; } /** * Performs an AssertJ soft assertion that there are exactly {@code numExpectedViolations} constraint violations * on the given object using a default validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may or may not have the expected values. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param object the object to validate * @param numExpectedViolations the number of violations that are expected * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects that were found when validating the object */ public static Set> assertViolations(SoftAssertions softly, T object, int numExpectedViolations, Class... groups) { return assertViolations(softly, VALIDATOR, object, numExpectedViolations, groups); } /** * Performs an AssertJ soft assertion that there are exactly {@code numExpectedViolations} constraint violations * on the given object using the specified validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may or may not have the expected values. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param validator the Validator instance to perform validation with * @param object the object to validate * @param numExpectedViolations the number of violations that are expected * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects that were found when validating the object */ public static Set> assertViolations(SoftAssertions softly, Validator validator, T object, int numExpectedViolations, Class... groups) { var violations = validator.validate(object, groups); softly.assertThat(violations).hasSize(numExpectedViolations); return violations; } /** * Asserts that there is exactly one constraint violation on the given object for the given {@code propertyName} * using a default validator. * * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param groups the optional validation groups to apply * @return the single {@link ConstraintViolation} object, when the assertion passes */ public static ConstraintViolation assertOnePropertyViolation(T object, String propertyName, Class... groups) { return assertOnePropertyViolation(VALIDATOR, object, propertyName, groups); } /** * Asserts that there is exactly one constraint violation on the given object for the given {@code propertyName} * using the specified validator. * * @param validator the Validator instance to perform validation with * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param groups the optional validation groups to apply * @return the single {@link ConstraintViolation} object, when the assertion passes */ public static ConstraintViolation assertOnePropertyViolation(Validator validator, T object, String propertyName, Class... groups) { var constraintViolations = assertPropertyViolations(validator, object, propertyName, 1, groups); return constraintViolations.iterator().next(); } /** * Performs an AssertJ soft assertion that there is exactly one constraint violation on the given object for the * given {@code propertyName} using a default validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may or may not have the expected values. This is also the reason it returns a * set instead of just a single object. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects that were found when validating the object */ public static Set> assertOnePropertyViolation(SoftAssertions softly, T object, String propertyName, Class... groups) { return assertOnePropertyViolation(softly, VALIDATOR, object, propertyName, groups); } /** * Performs an AssertJ soft assertion that there is exactly one constraint violation on the given object for the * given {@code propertyName} using the specified validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may or may not have the expected values. This is also the reason it returns a * set instead of just a single object. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param validator the Validator instance to perform validation with * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects that were found when validating the object */ public static Set> assertOnePropertyViolation(SoftAssertions softly, Validator validator, T object, String propertyName, Class... groups) { return assertPropertyViolations(softly, validator, object, propertyName, 1, groups); } /** * Asserts that there are no constraint violations on the given object for the * given {@code propertyName} using a default validator. * * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param groups the optional validation groups to apply */ public static void assertNoPropertyViolations(Object object, String propertyName, Class... groups) { assertNoPropertyViolations(VALIDATOR, object, propertyName, groups); } /** * Asserts that there are no constraint violations on the given object for the * given {@code propertyName} using the specified validator. * * @param validator the Validator instance to perform validation with * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param groups the optional validation groups to apply */ public static void assertNoPropertyViolations(Validator validator, Object object, String propertyName, Class... groups) { assertPropertyViolations(validator, object, propertyName, 0, groups); } /** * Performs an AssertJ soft assertion that there are no constraint violations on the given * object for the given {@code propertyName} using a default validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may not be empty. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects that were found when validating the object */ public static Set> assertNoPropertyViolations(SoftAssertions softly, T object, String propertyName, Class... groups) { return assertNoPropertyViolations(softly, VALIDATOR, object, propertyName, groups); } /** * Performs an AssertJ soft assertion that there are no constraint violations on the given * object for the given {@code propertyName} using the specified validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may not be empty. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param validator the Validator instance to perform validation with * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects that were found when validating the object */ public static Set> assertNoPropertyViolations(SoftAssertions softly, Validator validator, T object, String propertyName, Class... groups) { return assertPropertyViolations(softly, validator, object, propertyName, 0, groups); } /** * Asserts that there are exactly {@code numExpectedViolations} constraint violations on the given object * for the given {@code propertyName} using a default validator. * * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param numExpectedViolations the number of violations that are expected * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects, when the assertion passes */ public static Set> assertPropertyViolations(T object, String propertyName, int numExpectedViolations, Class... groups) { return assertPropertyViolations(VALIDATOR, object, propertyName, numExpectedViolations, groups); } /** * Asserts that there are exactly {@code numExpectedViolations} constraint violations on the given object * for the given {@code propertyName} using the specified validator. * * @param validator the Validator instance to perform validation with * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param numExpectedViolations the number of violations that are expected * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects, when the assertion passes */ public static Set> assertPropertyViolations(Validator validator, T object, String propertyName, int numExpectedViolations, Class... groups) { var propertyViolations = validator.validateProperty(object, propertyName, groups); assertThat(propertyViolations).describedAs(propertyName).hasSize(numExpectedViolations); return propertyViolations; } /** * Performs an AssertJ soft assertion that there are exactly {@code numExpectedViolations} constraint violations * on the given object for the given {@code propertyName} using a default validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may or may not have the expected values. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param numExpectedViolations the number of violations that are expected * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects that were found when validating the object */ public static Set> assertPropertyViolations(SoftAssertions softly, T object, String propertyName, int numExpectedViolations, Class... groups) { return assertPropertyViolations(softly, VALIDATOR, object, propertyName, numExpectedViolations, groups); } /** * Performs an AssertJ soft assertion that there are exactly {@code numExpectedViolations} constraint violations * on the given object for the given {@code propertyName} using the specified validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may or may not have the expected values. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param validator the Validator instance to perform validation with * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param numExpectedViolations the number of violations that are expected * @param groups the optional validation groups to apply * @return the set of {@link ConstraintViolation} objects that were found when validating the object */ public static Set> assertPropertyViolations(SoftAssertions softly, Validator validator, T object, String propertyName, int numExpectedViolations, Class... groups) { var propertyViolations = validator.validateProperty(object, propertyName, groups); softly.assertThat(propertyViolations).describedAs(propertyName).hasSize(numExpectedViolations); return propertyViolations; } /** * Asserts that the constraint violations match {@code expectedMessages} on the given object * for the given {@code propertyName} using a default validator. * * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param expectedMessages the exact validation messages that are expected * @return the set of {@link ConstraintViolation} objects, when the assertion passes */ public static Set> assertPropertyViolations(T object, String propertyName, String... expectedMessages) { return assertPropertyViolations(VALIDATOR, object, propertyName, expectedMessages); } /** * Asserts that the constraint violations match {@code expectedMessages} on the given object * for the given {@code propertyName} using the specified validator. * * @param validator the Validator instance to perform validation with * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param expectedMessages the exact validation messages that are expected * @return the set of {@link ConstraintViolation} objects, when the assertion passes */ public static Set> assertPropertyViolations(Validator validator, T object, String propertyName, String... expectedMessages) { var propertyViolations = validator.validateProperty(object, propertyName); var actualMessages = collectActualMessages(propertyViolations); var missingMessages = collectMissingMessages(actualMessages, expectedMessages); if (isNotNullOrEmpty(missingMessages)) { fail(buildFailureMessageForMissingMessages(actualMessages, missingMessages)); } return propertyViolations; } /** * Performs an AssertJ soft assertion that the constraint violations match {@code expectedMessages} on the given * object for the given {@code propertyName} using a default validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may or may not have the expected values. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param expectedMessages the exact validation messages that are expected * @return the set of {@link ConstraintViolation} objects */ public static Set> assertPropertyViolations(SoftAssertions softly, T object, String propertyName, String... expectedMessages) { return assertPropertyViolations(softly, VALIDATOR, object, propertyName, expectedMessages); } /** * Performs an AssertJ soft assertion that the constraint violations match {@code expectedMessages} on the given * object for the given {@code propertyName} using the specified validator. *

* Because this uses {@link SoftAssertions} and does not fail immediately, the returned set of * constraint violations may or may not have the expected values. * * @param softly an AssertJ SoftAssertions instance for collecting multiple errors * @param validator the Validator instance to perform validation with * @param object the object to validate * @param propertyName the name of the property to validate on the given object * @param expectedMessages the exact validation messages that are expected * @return the set of {@link ConstraintViolation} objects */ public static Set> assertPropertyViolations(SoftAssertions softly, Validator validator, T object, String propertyName, String... expectedMessages) { var propertyViolations = validator.validateProperty(object, propertyName); var actualMessages = collectActualMessages(propertyViolations); var missingMessages = collectMissingMessages(actualMessages, expectedMessages); if (isNotNullOrEmpty(missingMessages)) { softly.fail(buildFailureMessageForMissingMessages(actualMessages, missingMessages)); } return propertyViolations; } private static List collectActualMessages(Set> violations) { return violations.stream() .map(ConstraintViolation::getMessage) .toList(); } private static List collectMissingMessages(List actualMessages, String... expectedMessages) { return Arrays.stream(expectedMessages) .filter(value -> !actualMessages.contains(value)) .toList(); } private static String buildFailureMessageForMissingMessages(List actualMessages, List missingMessages) { return KiwiStrings.format("Messages [%s] not found in actual messages %s", String.join(", ", missingMessages), actualMessages); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy