泽西岛定制验证器unittest

时间:2017-02-08 04:22:39

标签: validation unit-testing jersey

我有一个用Jersey& amp;编写的REST服务。弹簧引导。我为POST参数编写了自定义验证器类。我想对它进行单元测试。我无法弄清楚如何做到这一点。我的验证器如下所示:

@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValidTaskForCreate.Validator.class)
public @interface ValidTaskForCreate {
     String message() default "Invalid Request to create a Task";
     Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
public class Validator implements ConstraintValidator<ValidTaskForCreate, Task> {

    @Override
    public void initialize(ValidTaskForCreate constraintAnnotation) {
    }

    @Override
    public boolean isValid(final Task task, ConstraintValidatorContext context) {
            context.disableDefaultConstraintViolation();
            if(task.getName() == null || task.getName().isEmpty()) {
                context.buildConstraintViolationWithTemplate("Task name should be specified").addConstraintViolation();
                return false;
            }

            if(task.getTaskType() == null)  {       
                context.buildConstraintViolationWithTemplate("Specify a valid TaskType in the range of [1..3]").addConstraintViolation();
                return false;
            }
            return true;
        }

    }
}

现在我想通过传递各种Task对象来测试isValid()函数。我不知道如何调用此方法。 我可以像这样创建Validator类的实例,

    ValidTaskForCreate.Validator taskValidator = null;
    taskValidator = new ValidTaskForCreate.Validator();

要调用isValid(),我可以使用taskValidator.isValid()。但我不知道如何创建ConstraintValidatorContext对象作为第二个参数传递。

或者是否有任何方法可以使用像这样的UnitTest自定义验证类?

2 个答案:

答案 0 :(得分:2)

  

但我不知道如何创建ConstraintValidatorContext对象作为第二个参数传递。

只需使用Mockito并嘲笑它。然后只需验证是否调用了正确的方法。这是在涉及依赖性时测试单元行为的方法。

private ConstraintValidatorContext context;
private ConstraintValidatorContext.ConstraintViolationBuilder builder;

@Before
public void setup() {
    // mock the context
    context = Mockito.mock(ConstraintValidatorContext.class);

    // context.buildConstraintViolationWithTemplate returns
    // ConstraintValidatorContext.ConstraintViolationBuilder
    // so we mock that too as you will be calling one of it's methods
    builder = Mockito.mock(ConstraintValidatorContext.ConstraintViolationBuilder.class);

    // when the context.buildConstraintViolationWithTemplate is called,
    // the mock should return the builder.
    Mockito.when(context.buildConstraintViolationWithTemplate(Mockito.anyString()))
        .thenReturn(builder);
}

@Test
public void test() {
    // call the unit to be tested
    boolean result = ..isValid(badTask, context);

    // assert the result
    assertThat(result).isFalse();

    // verify that the context is called with the correct argument
    Mockito.verify(context)
            .buildConstraintViolationWithTemplate("Task name should be specified");
}

请注意直接使用Mockito。在大多数情况下,您可能只是使用静态导入来减少冗长。我只是想让它更具可读性

答案 1 :(得分:0)

这是我发现使用标准 Spring 单元测试的最佳方式,无需模拟任何内容。

@RunWith(SpringRunner.class)
@SpringBootTest(classes= {ValidationAutoConfiguration.class})
public class AllowedValuesValidatorTest {
    @Autowired
    private Validator validator;

    @Test
    public void testIsValid() {
        ObjectToBeValidated obj = // create object

        Set<ConstraintViolation<ObjectToBeValidated>> violations = validator.validate(obj);
        boolean violationsFound =
            violations.stream().anyMatch(v -> v.getConstraintDescriptor().getAnnotation().annotationType().equals(
                    NonNullLowercaseLettersOrNumbersOnly.class));
        assertThat(externalIdViolationFound).isTrue();
    }
}

ValidationAutoConfiguration.class 作为测试的配置完成了繁重的工作。这将在 ObjectToBeValidated 上执行所有验证,您可以搜索您正在测试的违规行为。