2015-10-20 4 views
1

У меня есть перечисление, которое может быть представлено различными способами. Как String, как целое число и как Double (разные диапазоны), как Vector2D и, наконец, как значение enum. Вот обобщенный пример, значения не являются репрезентативными. Фактическое использование, которое у меня есть для этого, имеет более высокую ценность и методы.Junit тестирование сложных перечислений

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 значениями enum имеет 31 тест. Мне нужно, чтобы в версиях это достигало 33 значений enum. Это около 200 тестов.

Я надеялся использовать данные, управляемые тестированием, поскольку это упростило бы проверку тестовых данных на глаз.

Есть ли у кого-нибудь идеи относительно того, как установить это для перечисления? Все примеры тестов, основанных на данных, которые я нашел, имеют простой класс с одним методом тестирования.

+0

Для меня, похоже, вы не хотите проверять перечисление, но постоянными данными в перечислении. Чтобы проверить это, вы, вероятно, можете написать параметризованный тест, который запускает список тестов, принимая значение перечисления и ожидаемые результаты в качестве параметров. Таким образом, вы пишете только один (или более) тест на каждое значение, которое вы хотите протестировать, и затем можете запускать эти (эти) тесты во всех своих значениях перечисления. Если это то, что вы хотите, я мог бы привести вам пример ... –

+1

Какое свойство перечисления вы пытаетесь протестировать? –

+0

Показать некоторые из существующих тестов. – weston

ответ

2

Parameterized tests не самые красивые кусочки кода, каждый из которых задуман (мне не нравится весь объект []), но вы, вероятно, могли бы использовать их, чтобы делать ваши вещи ... В этом примере у меня есть два теста с ожидаемыми результатами, но, конечно, вы можете добавить много параметров для нескольких тестов, при каждом тестировании определенной части перечисления.

@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); 
    } 
} 

Таким образом, вы пишете только один набор тестов для самого перечисления, а затем параметризовать их с фактическими значениями перечислений и ожидаемым результатом для этих значений.

Я предлагаю выполнить фактические вычисления в классе тестирования, а не просто проверять значения, так как проверка значений приведет к тому, что люди скопируют &, вставляя их в свой тест, что никому не поможет.

+0

Параметрированный бегун JUnit - это боль, потому что вы не можете смешивать параметризованные с непараметрированными тестами. Действительно, с параметризованным все ваши тесты будут рассматриваться как параметризованные, поскольку параметры передаются конструктору. Если вы хотите иметь непараметрированные тесты, вам необходимо заключить весь тестовый класс в класс, аннотированный с помощью @RunWith (Enclosed.class), который, хотя и становится действительным, становится очень трудно читаемым. Поэтому я рекомендую использовать junitparams. – Kraal

0

Если у вас есть набор тестов для всех значений 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. JNnit's Parameterized.class запускает все ваши тесты для параметризации, и у вас не может быть разных наборов параметров для каждого метода тестирования. Вам нужно передать все параметры в свой конструктор. В результате вы не можете смешивать параметризованные тесты с непараметрированными. Если вы хотите иметь непараметрированные тесты или иметь разные наборы параметров, вам нужно заключить свои тестовые классы в класс, аннотированный @RunWith(Enclosed.class), который, хотя и действителен, становится очень трудным для чтения.

Вот почему я действительно рекомендую использовать JUnitParamsRunner.class вместо бегуна JNnit Parameterized.class.

Надеется, что это помогает,

Мишель

0

Я думаю, что опасность вы собираетесь в конечный итоге с полным дубликатом данных в ваших тестах 33 перечислений х 5 = 165 значений значения, будьте то используется параметризованный или нет, боль придет от копирования этих значений. И я не думаю, что этот подход даст вам более правильный код/​​данные. Если вы можете сделать ошибку в перечислении, вы можете сделать ту же ошибку в тесте.

Так что я бы проверил только пару из них, этого будет достаточно, чтобы проверить, как работают аксессоры.

Тогда этот enum должен использоваться другими классами. Я бы сосредоточился на тестировании этих классов, чтобы, если эти значения ошибочны, код будет терпеть неудачу. На самом деле мой подход состоял бы в том, чтобы добавить дополнительные перечисления, поскольку они необходимы только для того, чтобы пройти другие тесты.

+0

Я бы не дублировал данные, я бы сделал что-то для данных и протестировал против ожидаемого результата. Это, по меньшей мере, уменьшает вероятность ошибки данных. Но, конечно, мы могли бы утверждать, что тестирование базовых данных в рамках единичного теста ... –

+0

@FlorianSchaetz вы это говорите, но ваш ответ показывает дублирование данных в тестах. Похоже, вы согласны со мной. – weston

+0

Это просто потому, что мои данные должны были быть примером, для реальной вещи я ожидал бы, что тест сделает что-то с данными, а затем сравните результат с ожидаемым значением. Вот почему я не называл методы «get ...», но «doSomething». Я сделаю это более ясным. –

0

Если вы хотите убедиться, что ввод данных был выполнен правильно, не надо проверить каждый перечислитель отдельно - это бессмысленно. было бы очень легко с параметризированного тестирования, но вы будете в конечном итоге только с копией вашего производства кода:

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

это не мешает некорректный ввод данных каким-либо образом. это просто заставляет процесс изменения кода дольше (из-за дублирования). если кто-то напечатает плохие данные, он просто скопирует их в тесты

вместо этого попробуйте проверить, сохраняются ли все необходимые свойства. например, все значения должны быть разными, а не перекрываться, равномерно распределяться, иметь последующие значения и т. д., проверить, как другой код реагирует на перечисление. например, если все возможные события запущены, если метод получает все перечисления.

Таким образом, когда кто-то изменяет перечисление, тесты остаются неизмененными. это позволяет в некоторой степени обнаружить неверные данные.

Смежные вопросы