2

我有一个可以以多种不同方式呈现的枚举。作为字符串,作为整数和作为双精度(不同范围),作为 Vector2D,最后作为枚举值本身。这是一个通用示例,这些值不具有代表性。我对此的实际使用具有更多的价值和方法。

 public enum Example {

    value0("Name0", 0, 0.0, 0.01707, 0.12534);        
    value1("Name1", 1, 25.0, 0.1707, 0.53434);
    value2("Name2", 2, 55.0, 0.70701, 0.23534);
    value3("Name3", 3, 65.0, 0.01707, 0.34786);
    value5("Name4", 4, 100.0, 0.01707, 0.42594);

    private final String name;
    private final int number; 
    private final double head;
    private final Vector2d pointVec;

    /**
     * Constructor invoked for each value above. 
     */
    enumExample(String name, int no, double hdg, float compX, float CompY) {
      this.name = name;
      this.number = no;
      this.head = hdg;
      this.pointVec = new Vector2d(compX, compY);
    }

    public String getName(){
       return name;        
    }

    public int getNumber() {
        return no;
    }

    public int getHead() {
        return head;
    }

    public Vector2D getVector() {
        return pointVec;
    }        

    public Example getCalcValue(int value) {
        return calcValue(getNumber(value));
    }

    /*
     * There are more methods that perform calculations on the enum's 
     * attributes.
     */
 }

为了确保使用此枚举的其他类使用正确功能的枚举。我想对其进行一套全面的测试,从而确保数据输入已正确执行,并且枚举及其相关数据没有损坏。

目前,具有 5 个枚举值的示例有 31 个测试。我需要最多 33 个枚举值的版本。大约是 200 次测试。

我希望能够使用数据驱动测试,因为这将使通过肉眼检查测试数据变得更加容易。

有人对如何为枚举进行设置有任何想法吗?我发现的所有数据驱动测试的例子都有一个简单的类,只有一种测试方法。

4

4 回答 4

2

参数化测试并不是每个人都能想到的最漂亮的代码片段(我不喜欢整个 object[] 的东西),但你可能会用它们来做你的东西......在这个例子中,我有两个测试结果符合预期,但是当然,您可以为多个测试添加许多参数,每个测试都测试枚举的某个部分。

@RunWith(Parameterized.class)
public class SomeTest {

    @Parameters
    public static Iterable<Object[]> data() {
        return Arrays.asList(new Object[][] { 
                 { MyEnum.Value1, 0, "x" }, 
                 { MyEnum.Value2, 1, null }, 
                 { MyEnum.Value3, 127, "y" }, 
                 etc.
           });
    }

    private MyEnum enumValue;
    private int expectedInt;
    private String expectedString;

    // Each test set will get one set of parameters from your array
    public SomeTest(MyEnum enumValue, int expectedInt, String expectedString) {
        this.enumValue = enumValue;
        this.expectedInt = expectedInt;
        this.expectedString = expectedString;
    }

    @Test
    public void testInt() {
         // do whatever calculation you need to do on the data
         int result = this.enumValue.doSomething() * 2 - 100;  
         assertEquals(expectedInt, result);
    }

    @Test
    public void testString() {
         // do whatever calculation you need to do on the data
         String result = this.enumValue.doSomethingElse().substring(2,5);
         assertEquals(expectedString, result);
    }
}

这样,您只需为枚举本身编写一组测试,然后使用实际的枚举值和这些值的预期结果对它们进行参数化。

我建议在测试类中进行实际计算,而不仅仅是检查值,因为检查值会导致人们将它们复制并粘贴到您的测试中,这对任何人都没有帮助。

于 2015-10-20T08:04:11.710 回答
1

如果您要对所有 Enum 值进行一组测试,则应尝试将参数化测试与JUnitparams一起使用。

以下是如何使用 JUnitParams 的示例:

@RunWith(JUnitParamsRunner.class)
public class ExampleTest {

    //...

    /**
     * This test is parameterized !
     */
    @Test
    @Parameters
    public void yourTestMethod(ExampleEnum enumValue, Integer inputValue, String expectedString /* other parameters if you need them */) {
        // here you test what you need to test
        // for instance stupid dummy test
        assertEquals(enumValue.doSomething(inputValue), expectedString);
    }

    /**
     * This method provides the parameters values for the "yourTestMethod"
     * test. Note that there is a naming convention to be followed ! 
     * You need to prefix your test method's name with "parametersFor"
     */
    private Object[] parametersForYourTestMethod() { 
        return new Object[] {
            // each Object[] is a test case where elements are
            // inputs and / or expected outputs
            new Object[] { 
                ExampleEnum.CASE_1,
                1,
                "ExpectedString1"
            },
            new Object[] {
                ExampleEnum.CASE_2,
                2,
                "ExpectedString2"
            },
            new Object[] {
                ExampleEnum.CASE_3,
                3,
                "ExpectedString3"
            },
            new Object[] {
                ExampleEnum.CASE_4,
                4,
                "ExpectedString4"
            },
            // ... add as many test cases as you need
            new Object[] {
                ExampleEnum.CASE_N,
                Integer.MAX_VALUE,
                "ExpectedStringN"
            }
        }
    }

    //...

    /**
     * This test is not parameterized !
     */
    @Test
    public void anotherTest() {
        //...
    }
}

这个测试类为您提供了一个@Test命名yourTestMethod的运行N时间,每次都使用parametersForYourTestMethod方法提供的一组不同的参数。您可以使用所需的任何输入组合添加任意数量的参数化测试。

请注意,此类也有一个非参数化的@Test命名anotherTest()

最后一点说明了 JUnitParams 扩展提供的优于“纯”JUnit 使用的优势。JUnit 的运行程序会Parameterized.class强制对所有测试进行参数化,并且您不能为每种测试方法设置不同的参数集。您需要将所有参数传递给您的构造函数。因此,您不能将参数化测试与非参数化测试混合使用。如果您想要进行非参数化测试或具有不同的参数集,那么您需要将您的测试类包含在一个带有注释的类@RunWith(Enclosed.class)中,虽然有效,但很难阅读。

这就是为什么我真的推荐使用JUnitParamsRunner.class而不是 JUnit 的Parameterized.class跑步者。

希望能帮助到你,

米歇尔

于 2015-10-20T08:14:14.437 回答
0

我认为危险在于您最终会在测试中得到完整的数据副本 33 个枚举 x 5 个值 = 165 个值,无论您是否使用参数化,复制这些值都会带来痛苦。而且我认为这种方法不会为您提供更正确的代码/数据。如果你能在枚举中犯错,你也可以在测试中犯同样的错误。

所以我只会测试其中的几个,这足以测试访问器是否正常工作。

那么这enum必须被其他类使用。我会专注于测试这些类,这样如果这些值错误,代码就会失败。事实上,我的方法是添加额外的枚举,因为它们只需要让其他测试通过。

于 2015-10-20T08:15:33.040 回答
0

如果您想确保数据输入已正确执行,请不要单独测试每个枚举 - 这是没有意义的。参数化测试会很容易,但你最终只会得到一份生产代码的副本:

test(enum0, "Name0", 0, 0.0, 0.01707, 0.12534)
test(enum1, "Name1", 1, 25.0, 0.1707, 0.53434)

它不会以任何方式阻止格式错误的数据输入。它只是使代码更改过程更长(因为重复)。如果有人输入了错误的数据,他只会将它们复制粘贴到测试中

而是尝试检查是否所有必需的属性都成立。例如,所有值必须不同,不能重叠,均匀分布,具有后续值等。检查其他代码对枚举的反应。例如,如果一个方法接收到所有枚举,所有可能的事件都会被触发。

这样,当有人更改枚举时,测试保持不变。它可以让您在某种程度上检测格式错误的数据

于 2015-10-25T10:59:23.817 回答