Search code examples
javavalidationjunitannotationsbean-validation

JUnit-Testing Custom Validation Annotations Java


Hei,

I currently working on custom annotations for bean validation. To ensure the implemented validation logic is working as intended, i would like to implement unit-tests for these annotations. Sadly I am struggeling to find relevant guides/tutorials on Google.

The most obvious solution is to create some class, stick the annotation on it and use the validatorFactory to start the validation as usual. With this, we would be able to see if the expected results came in. But that approach is not a real unit-Test. Various other parts of the bean validation logic are run through to carry out the test.

I do think it would be preferrable to test the validators independently, but I have no clue how to manually do so. After creating the instance of the validator, we would need to pass the annotation to its initialize function. But how can i manually produce this instance of an annotation? Is this even possible?

Annotation-Code:

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Constraint(validatedBy = { LongRangeValidator.class })
@Documented
public @interface LongRange {

    /**
     * Minimal valid value
     */
    long min() default 0;

    /**
     * Maximal valid value
     */
    long max() default Long.MAX_VALUE;

    String message() default "";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    @interface List {
        LongRange[] value();
    }

}

Validator-Code:

/**
 * Validator for @LongRange-Annotation
 */
public class LongRangeValidator implements ConstraintValidator<LongRange, Long> {

    private Long min;
    private Long max;

    @Override
    public void initialize(final LongRange constraintAnnotation) {
        min = constraintAnnotation.min();
        max = constraintAnnotation.max();
    }

    @Override
    public boolean isValid(final Long value, final ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }

        return min.compareTo(value) <= 0 && max.compareTo(value) >= 0;
    }
}

Sincerely,

WorkingAccount


Solution

  • Ok, silly problem. I did not get how to instanciate an interface. I solved it as follows:

    In the Test-Class I added a method for creating the instance of the Annotation. Note that all of the interface-Methods aswell als the annotationType-Method must be implemented.

    private LongRange createLongRange(long min, long max) {
            return new LongRange() {
                @Override
                public long min() {
                    return min;
                }
    
                @Override
                public long max() {
                    return max;
                }
    
                @Override
                public String message() {
                    return "MSG_1";
                }
    
                @Override
                public Class<?>[] groups() {
                    return new Class[0];
                }
    
                @Override
                public Class<? extends Payload>[] payload() {
                    return new Class[0];
                }
    
                @Override
                public Class<? extends Annotation> annotationType() {
                    return LongRange.class;
                }
            };
        }
    
    

    Having this method we can set up the validator for the testcase with the following logic.

    private void setUp(long min, long max) {
            this.longRangeValidator = new LongRangeValidator();
            this.longRangeValidator.initialize(createLongRange(min, max));
        }
    

    With that I am able to write unit tests for my annotation.