Search code examples
javajakarta-eejavax.validation

How to validate parameters of a static method in JUnit?


I have a static method with parameters and constraints. I want to run some unit tests but when I call executableValidator.validateParameters, no violations issues are raised (it should be)

I run some reflection code and I display correctly the validation annotation in the log.

My class with the static method:

public class DiceRoller {

    private DiceRoller(){}
    public static int roll(@Max(20) @Valid Integer number, @DiceConstraint @Valid Integer sides){
        return (int) Math.floor(Math.random() * ((sides * number)-number) + number);
    }

}

The constraint interface:

@Documented
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DiceValidator.class)
public @interface DiceConstraint {

    String message() default "You have to choose between dice with 2,4,6,8,10,12,20 or 100 sides";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

}

the validator class:

public class DiceValidator implements ConstraintValidator<DiceConstraint, Integer> {

    protected int validSides [] = {2,4,6,8,10,12,20,100};

    @Override
    public boolean isValid(Integer sides, ConstraintValidatorContext constraintValidatorContext) {
        return Arrays.stream(validSides).anyMatch(i -> i == sides.intValue());

    }
}

and my test:

@SpringBootTest(classes = {SpringBootCharacterApplication.class})
public class DiceRollerCoCTest {

    private static ValidatorFactory factory;
    private static Validator validator;
    private static ExecutableValidator executableValidator;

    @BeforeEach
    public void setUp() {
        if (factory == null) {
            factory = Validation.buildDefaultValidatorFactory();
            validator = factory.getValidator();
            executableValidator = validator.forExecutables();
        }
    }

    @Test
    void roll() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        log.debug("Test of DiceRoller.roll(1000, 1000)");
        Method roll = DiceRoller.class.getDeclaredMethod("roll", Integer.class,Integer.class);
        Annotation[][] parameterAnnotations = roll.getParameterAnnotations();
        Arrays.stream(parameterAnnotations)
                .forEach(v->
                        Arrays.stream(v)
                                .forEach(vv -> log.debug(vv.toString())) );
        log.debug("Invocation " + roll.invoke(null, 1000, 1000));
        Object [] parameterValues = {1000, 1000};
        Set<ConstraintViolation<Object>> violations
                = executableValidator.validateParameters(
                        DiceRoller.class,
                        roll,
                        parameterValues);
        log.debug(violations.size());

    }
}

On the last part:

Object [] parameterValues = {1000, 1000};
        Set<ConstraintViolation<Object>> violations
                = executableValidator.validateParameters(
                        DiceRoller.class,
                        roll,
                        parameterValues);
        log.debug(violations.size());

The violations size should be equal to 2 but it is equal to 0.

I have also a RestController using the method with the @Validated annotation on top and in this case it is working. So I'm waiting the same behavior when I run this unit test.

What is my mistake? Thanks


Solution

  • The name "bean validation framework" suggests that it only applies to Java Beans, which are always objects and static methods don't technically belong to the Bean's concept.

    This is the first statement of this page: https://javaee.github.io/tutorial/bean-validation004.html

    "Bean Validation constraints may be placed on the parameters of nonstatic methods and constructors and on the return values of nonstatic methods. Static methods and constructors will not be validated."