Есть ли способ задать собственные имена тестовых примеров при использовании параметризованных тестов в JUnit4?
Я хочу изменить значение по умолчанию - [Test class].runTest[n] - на что-то значимое.
Есть ли способ задать собственные имена тестовых примеров при использовании параметризованных тестов в JUnit4?
Я хочу изменить значение по умолчанию - [Test class].runTest[n] - на что-то значимое.
Эта функция превратила ее в JUnit 4.11.
Чтобы использовать изменение имени параметризованных тестов, вы говорите:
@Parameters(name="namestring")
 namestring - строка, которая может иметь следующие специальные заполнители:
{index} - индекс этого набора аргументов. Значение по умолчанию namestring равно {index}.{0} - первое значение параметра из этого вызова теста.{1} - второе значение параметраКонечным именем теста будет имя метода тестирования, за которым следует namestring в скобках, как показано ниже.
Например (адаптировано из unit test для аннотации Parameterized):
@RunWith(Parameterized.class)
static public class FibonacciTest {
    @Parameters( name = "{index}: fib({0})={1}" )
    public static Iterable<Object[]> data() {
        return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
                { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
    }
    private final int fInput;
    private final int fExpected;
    public FibonacciTest(int input, int expected) {
        fInput= input;
        fExpected= expected;
    }
    @Test
    public void testFib() {
        assertEquals(fExpected, fib(fInput));
    }
    private int fib(int x) {
        // TODO: actually calculate Fibonacci numbers
        return 0;
    }
}
даст имена типа testFib[1: fib(1)=1] и testFib[4: fib(4)=3]. (testFib часть имени - это имя метода @Test).
Глядя на JUnit 4.5, его бегун явно не поддерживает это, поскольку эта логика скрыта внутри частного класса внутри класса Parameterized. Вы не могли использовать JUnit Parameterized runner и сами создавать свои собственные, чтобы понять концепцию имен (что приводит к вопросу о том, как вы можете установить имя...).
С точки зрения JUnit было бы неплохо, если бы вместо (или в дополнение к) просто передавали приращение, они передавали аргументы с разделителями-запятыми. TestNG делает это. Если эта функция важна для вас, вы можете прокомментировать список рассылки yahoo, указанный на сайте www.junit.org.
Недавно я столкнулся с одной проблемой при использовании JUnit 4.3.1. Я внедрил новый класс, который расширяет параметр Parameterized под названием LabelledParameterized. Он был протестирован с использованием JUnit 4.3.1, 4.4 и 4.5. Он восстанавливает экземпляр Description, используя представление String первого аргумента каждого массива параметров из метода @Parameters. Вы можете увидеть код для этого по адресу:
http://code.google.com/p/migen/source/browse/trunk/java/src/.../LabelledParameterized.java? г = 3789
и пример его использования:
http://code.google.com/p/migen/source/browse/trunk/java/src/.../ServerBuilderTest.java? г = 3789
Формальное описание теста хорошо написано в Eclipse, что я и хотел, так как это делает неудачные тесты намного легче найти! Я, вероятно, буду дополнительно уточнять и документировать классы в течение следующих нескольких дней/недель. Отбросить '?' часть URL-адресов, если вы хотите края кровотечения.: -)
Чтобы использовать его, все, что вам нужно сделать, это скопировать этот класс (GPL v3) и изменить @RunWith (Parameterized.class) на @RunWith (LabelledParameterized.class), предполагая, что первым элементом вашего списка параметров является разумная метка.
Я не знаю, будут ли какие-либо последующие выпуски JUnit адресовать эту проблему, но даже если бы они это сделали, я не могу обновить JUnit, так как все мои со-разработчики тоже должны были бы обновить, и у нас есть более высокие приоритеты, чем повторная настройка. Следовательно, работа в классе должна быть скомпилирована несколькими версиями JUnit.
Примечание. есть некоторое отражение jiggery-pokery, так что оно проходит через разные версии JUnit, перечисленные выше. Версия специально для JUnit 4.3.1 можно найти здесь и для JUnit 4.4 и 4.5 .
С Parameterized в качестве модели я написал свой собственный тестовый бегун/набор - всего около получаса. Он немного отличается от darrenp LabelledParameterized тем, что позволяет явно указывать имя, а не полагаться на первый параметр toString().
Он также не использует массивы, потому что я ненавижу массивы.:)
public class PolySuite extends Suite {
  // //////////////////////////////
  // Public helper interfaces
  /**
   * Annotation for a method which returns a {@link Configuration}
   * to be injected into the test class constructor
   */
  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.METHOD)
  public static @interface Config {
  }
  public static interface Configuration {
    int size();
    Object getTestValue(int index);
    String getTestName(int index);
  }
  // //////////////////////////////
  // Fields
  private final List<Runner> runners;
  // //////////////////////////////
  // Constructor
  /**
   * Only called reflectively. Do not use programmatically.
   * @param c the test class
   * @throws Throwable if something bad happens
   */
  public PolySuite(Class<?> c) throws Throwable {
    super(c, Collections.<Runner>emptyList());
    TestClass testClass = getTestClass();
    Class<?> jTestClass = testClass.getJavaClass();
    Configuration configuration = getConfiguration(testClass);
    List<Runner> runners = new ArrayList<Runner>();
    for (int i = 0, size = configuration.size(); i < size; i++) {
      SingleRunner runner = new SingleRunner(jTestClass, configuration.getTestValue(i), configuration.getTestName(i));
      runners.add(runner);
    }
    this.runners = runners;
  }
  // //////////////////////////////
  // Overrides
  @Override
  protected List<Runner> getChildren() {
    return runners;
  }
  // //////////////////////////////
  // Private
  private Configuration getConfiguration(TestClass testClass) throws Throwable {
    return (Configuration) getConfigMethod(testClass).invokeExplosively(null);
  }
  private FrameworkMethod getConfigMethod(TestClass testClass) {
    List<FrameworkMethod> methods = testClass.getAnnotatedMethods(Config.class);
    if (methods.isEmpty()) {
      throw new IllegalStateException("@" + Config.class.getSimpleName() + " method not found");
    }
    if (methods.size() > 1) {
      throw new IllegalStateException("Too many @" + Config.class.getSimpleName() + " methods");
    }
    FrameworkMethod method = methods.get(0);
    int modifiers = method.getMethod().getModifiers();
    if (!(Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
      throw new IllegalStateException("@" + Config.class.getSimpleName() + " method \"" + method.getName() + "\" must be public static");
    }
    return method;
  }
  // //////////////////////////////
  // Helper classes
  private static class SingleRunner extends BlockJUnit4ClassRunner {
    private final Object testVal;
    private final String testName;
    SingleRunner(Class<?> testClass, Object testVal, String testName) throws InitializationError {
      super(testClass);
      this.testVal = testVal;
      this.testName = testName;
    }
    @Override
    protected Object createTest() throws Exception {
      return getTestClass().getOnlyConstructor().newInstance(testVal);
    }
    @Override
    protected String getName() {
      return testName;
    }
    @Override
    protected String testName(FrameworkMethod method) {
      return testName + ": " + method.getName();
    }
    @Override
    protected void validateConstructor(List<Throwable> errors) {
      validateOnlyOneConstructor(errors);
    }
    @Override
    protected Statement classBlock(RunNotifier notifier) {
      return childrenInvoker(notifier);
    }
  }
}
И пример:
@RunWith(PolySuite.class)
public class PolySuiteExample {
  // //////////////////////////////
  // Fixture
  @Config
  public static Configuration getConfig() {
    return new Configuration() {
      @Override
      public int size() {
        return 10;
      }
      @Override
      public Integer getTestValue(int index) {
        return index * 2;
      }
      @Override
      public String getTestName(int index) {
        return "test" + index;
      }
    };
  }
  // //////////////////////////////
  // Fields
  private final int testVal;
  // //////////////////////////////
  // Constructor
  public PolySuiteExample(int testVal) {
    this.testVal = testVal;
  }
  // //////////////////////////////
  // Test
  @Ignore
  @Test
  public void odd() {
    assertFalse(testVal % 2 == 0);
  }
  @Test
  public void even() {
    assertTrue(testVal % 2 == 0);
  }
}
из junit4.8.2, вы можете создать свой собственный класс MyParameterized, просто скопировав класс Parameterized. измените методы getName() и testName() в TestClassRunnerForParameters.
Вы также можете попробовать JUnitParams: http://code.google.com/p/junitparams/
Вы можете создать такой метод, как
@Test
public void name() {
    Assert.assertEquals("", inboundFileName);
}
Хотя я бы не использовал его все время, было бы полезно выяснить, какой именно номер теста 143.
Я широко использую статический импорт для Assert и друзей, поэтому мне легко переопределить утверждение:
private <T> void assertThat(final T actual, final Matcher<T> expected) {
    Assert.assertThat(editThisToDisplaySomethingForYourDatum, actual, expected);
}
Например, вы можете добавить поле "имя" в ваш тестовый класс, инициализироваться в конструкторе и отобразить это при ошибке тестирования. Просто передайте его в качестве первых элементов массива параметров для каждого теста. Это также помогает маркировать данные:
public ExampleTest(final String testLabel, final int one, final int two) {
    this.testLabel = testLabel;
    // ...
}
@Parameters
public static Collection<Object[]> data() {
    return asList(new Object[][]{
        {"first test", 3, 4},
        {"second test", 5, 6}
    });
}
Ни один из них не работал у меня, поэтому я получил источник для параметра Parameterized и изменил его, создав новый тестовый бегун. Мне не пришлось много менять, но ЭТО РАБОТАЕТ!!!
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.junit.Assert;
import org.junit.internal.runners.ClassRoadie;
import org.junit.internal.runners.CompositeRunner;
import org.junit.internal.runners.InitializationError;
import org.junit.internal.runners.JUnit4ClassRunner;
import org.junit.internal.runners.MethodValidator;
import org.junit.internal.runners.TestClass;
import org.junit.runner.notification.RunNotifier;
public class LabelledParameterized extends CompositeRunner {
static class TestClassRunnerForParameters extends JUnit4ClassRunner {
    private final Object[] fParameters;
    private final String fParameterFirstValue;
    private final Constructor<?> fConstructor;
    TestClassRunnerForParameters(TestClass testClass, Object[] parameters, int i) throws InitializationError {
        super(testClass.getJavaClass()); // todo
        fParameters = parameters;
        if (parameters != null) {
            fParameterFirstValue = Arrays.asList(parameters).toString();
        } else {
            fParameterFirstValue = String.valueOf(i);
        }
        fConstructor = getOnlyConstructor();
    }
    @Override
    protected Object createTest() throws Exception {
        return fConstructor.newInstance(fParameters);
    }
    @Override
    protected String getName() {
        return String.format("%s", fParameterFirstValue);
    }
    @Override
    protected String testName(final Method method) {
        return String.format("%s%s", method.getName(), fParameterFirstValue);
    }
    private Constructor<?> getOnlyConstructor() {
        Constructor<?>[] constructors = getTestClass().getJavaClass().getConstructors();
        Assert.assertEquals(1, constructors.length);
        return constructors[0];
    }
    @Override
    protected void validate() throws InitializationError {
        // do nothing: validated before.
    }
    @Override
    public void run(RunNotifier notifier) {
        runMethods(notifier);
    }
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface Parameters {
}
private final TestClass fTestClass;
public LabelledParameterized(Class<?> klass) throws Exception {
    super(klass.getName());
    fTestClass = new TestClass(klass);
    MethodValidator methodValidator = new MethodValidator(fTestClass);
    methodValidator.validateStaticMethods();
    methodValidator.validateInstanceMethods();
    methodValidator.assertValid();
    int i = 0;
    for (final Object each : getParametersList()) {
        if (each instanceof Object[])
            add(new TestClassRunnerForParameters(fTestClass, (Object[]) each, i++));
        else
            throw new Exception(String.format("%s.%s() must return a Collection of arrays.", fTestClass.getName(), getParametersMethod().getName()));
    }
}
@Override
public void run(final RunNotifier notifier) {
    new ClassRoadie(notifier, fTestClass, getDescription(), new Runnable() {
        public void run() {
            runChildren(notifier);
        }
    }).runProtected();
}
private Collection<?> getParametersList() throws IllegalAccessException, InvocationTargetException, Exception {
    return (Collection<?>) getParametersMethod().invoke(null);
}
private Method getParametersMethod() throws Exception {
    List<Method> methods = fTestClass.getAnnotatedMethods(Parameters.class);
    for (Method each : methods) {
        int modifiers = each.getModifiers();
        if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))
            return each;
    }
    throw new Exception("No public static parameters method on class " + getName());
}
public static Collection<Object[]> eachOne(Object... params) {
    List<Object[]> results = new ArrayList<Object[]>();
    for (Object param : params)
        results.add(new Object[] { param });
    return results;
}
}
Обходным путем было бы уловить и вложить все Throwables в новый Throwable с помощью специального сообщения, содержащего всю информацию о параметрах. Сообщение появится в трассировке стека. Это работает всякий раз, когда тест терпит неудачу для всех утверждений, ошибок и исключений, поскольку все они являются подклассами Throwable.
Мой код выглядит следующим образом:
@RunWith(Parameterized.class)
public class ParameterizedTest {
    int parameter;
    public ParameterizedTest(int parameter) {
        super();
        this.parameter = parameter;
    }
    @Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] { {1}, {2} });
    }
    @Test
    public void test() throws Throwable {
        try {
            assertTrue(parameter%2==0);
        }
        catch(Throwable thrown) {
            throw new Throwable("parameter="+parameter, thrown);
        }
    }
}
Трассировка стека неудавшегося теста:
java.lang.Throwable: parameter=1
    at sample.ParameterizedTest.test(ParameterizedTest.java:34)
Caused by: java.lang.AssertionError
    at org.junit.Assert.fail(Assert.java:92)
    at org.junit.Assert.assertTrue(Assert.java:43)
    at org.junit.Assert.assertTrue(Assert.java:54)
    at sample.ParameterizedTest.test(ParameterizedTest.java:31)
    ... 31 more
Отметьте JUnitParams как упомянутый dsaff, работает с помощью ant для создания параметризованных описаний методов тестирования в отчете html.
Это было сделано после попытки LabelledParameterized и определения того, что, хотя он работает с eclipse, он не работает с ant в отношении отчета html.
Приветствия,
Поскольку доступ к параметру (например, с помощью "{0}" всегда возвращает представление toString(), одним из способов было бы сделать анонимную реализацию и переопределить toString() в каждом случае. Например:
public static Iterable<? extends Object> data() {
    return Arrays.asList(
        new MyObject(myParams...) {public String toString(){return "my custom test name";}},
        new MyObject(myParams...) {public String toString(){return "my other custom test name";}},
        //etc...
    );
}