JUnit - 使用数据集测试bean验证的最佳实践

时间:2017-05-01 09:02:33

标签: java unit-testing junit junit4 bean-validation

我想编写单元测试,它验证了bean验证约束的正确配置。我认为应该对数据集进行测试,因此它会验证许多不同的组合。

到目前为止,我制作了这段代码:

@RunWith(Parameterized.class)
public class TagTest {

    private Validator validator;

    @Parameterized.Parameter
    public Pair<Boolean, Tag> tagPair;

    @Parameterized.Parameters
    public static Collection<Pair<Boolean, Tag>> testData() {

        Collection<Pair<Boolean, Tag>> tags = new ArrayList<>();

        Tag tag = new Tag();
        tag.setId(1L);
        tag.setVersion(1L);
        tag.setTitle("Sample");
        tags.add(new ImmutablePair<>(true, tag));

        // ... more sample data

        return tags;
    }

    @Before
    public void init() {
        ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
        this.validator = vf.getValidator();
    }

    @Test
    public void shouldBeValidated() {        
        Set<ConstraintViolation<Tag>> violations = validator.validate(
                tagPair.getRight());

        Assert.assertTrue(violations.isEmpty() == tagPair.getLeft());
    }  
}

从中读取样本数据的最佳解决方案是什么?在代码中保存数据对我来说并不合适。我的例子中的标签是扁平物体。如果对象会很复杂怎么办?

单元测试是否可以接受,我会对bean验证进行一般测试,这将接受Object(在我的情况下代替Tag),然后验证我将推送的任何数据?

1 个答案:

答案 0 :(得分:0)

尽量保持简单。例如。尽量使测试数据接近测试逻辑。有两种或多或少的好方法可以实现您的需求:

  • 使用TestNG及其@DataProvider
  • 使用JUnit并在一次测试中保留许多测试。虽然通常最好的做法是将测试分成不同的测试方法以进行验证,但我认为您可以违反此规则。这是因为验证测试​​太多而且非常简单(参见下面的示例)。

你也可以转向像Spock这样提供最好的数据提供者的其他框架,但它们通常用动态语言(如Groovy)编写,这会带来更多弊大于利。

另一种选择当然是使用@RunWith(Parameterized.class)。但这是一个非常奇怪的机制,我没有看到有人在现实生活中使用它,因为它有多么不方便。您还可以查看@Theory

这是JUnit的真实例子:

@Test public void validationMustPass_forValidExperimentName() {
    assertExperimentNameValidationPasses("Min boundary", alphanumeric(1));
    assertExperimentNameValidationPasses("Max boundary", alphanumeric(20));
    assertExperimentNameValidationPasses("With all alphanumerics and allowed special characters",
            between(2, 19).with(multipleOf("_-")).alphanumeric());
    assertExperimentNameValidationPasses("With spaces", between(2, 19).with(oneOf(" ")).alphanumeric());
    assertExperimentNameValidationPasses("Only numbers", between(2, 19).numeric());
    assertExperimentNameValidationPasses("Only dashes", between(2, 19).string('-'));
    assertExperimentNameValidationPasses("Only underscores", between(2, 19).string('_'));
}

@Test public void mustNotCreateExperimentWithWrongExperimentName() {
    assertExperimentNameValidationFails(
            "Longer than max allowed length",
            "Should be between 1 and 20 symbols.",
            length(21).alphanumeric());
    assertExperimentNameValidationFails("Experiment name is white space",
            "Should be between 1 and 20 symbols.",
            "  ");
    assertExperimentNameValidationFails("Experiment name is empty",
            "Should be between 1 and 20 symbols.",
            "");
    assertExperimentNameValidationFails("Experiment name contains not allowed symbols",
            "Only English letters, numbers, spaces, dashes and underscores are allowed",
            length(10).with(oneOf(FORBIDDEN_CHARACTERS)).alphanumeric());
}

这仅仅是对象的1个字段。这是doing this with Spock的一个例子,但正如我所提到的 - 它通常是不值得的。以下是keep data management effective的一些基本规则。