Cambio de nombres de pruebas parametrizadas

votos
168

¿Hay alguna manera de establecer mis propios nombres de caso de prueba personalizados cuando se utilizan pruebas parametrizadas en JUnit4?

Me gustaría cambiar el valor predeterminado - [Test class].runTest[n]- a algo significativo.

Publicado el 16/03/2009 a las 16:25
fuente por usuario
En otros idiomas...                            


12 respuestas

votos
37

En cuanto a JUnit 4.5, su corredor claramente no lo admite, ya que esa lógica está enterrada dentro de una clase privada dentro de la clase Parametrizada. No podría usar el corredor JUnit Parameterized, y crear el suyo propio que comprendería el concepto de nombres (lo que lleva a la pregunta de cómo puede establecer un nombre ...).

Desde la perspectiva de JUnit, sería bueno si en lugar de (o además de) solo pasasen un incremento, pasarían los argumentos delimitados por comas. TestNG hace esto. Si la característica es importante para usted, puede hacer un comentario en la lista de correo de yahoo a la que se hace referencia en www.junit.org.

Respondida el 16/03/2009 a las 16:49
fuente por usuario

votos
2

Puedes crear un método como

@Test
public void name() {
    Assert.assertEquals("", inboundFileName);
}

Si bien no lo usaría todo el tiempo, sería útil averiguar exactamente qué prueba es el número 143.

Respondida el 10/08/2009 a las 21:23
fuente por usuario

votos
21

Recientemente me encontré con el mismo problema cuando se utiliza JUnit 4.3.1. He implementado una nueva clase que se extiende parametrizado llama LabelledParameterized. Se ha probado el uso de JUnit 4.3.1, 4.4 y 4.5. Se reconstruye la instancia Descripción usando la representación de cadena del primer argumento de cada matriz de parámetros del método @Parameters. Puede ver el código para esto en:

http://code.google.com/p/migen/source/browse/trunk/java/src/.../LabelledParameterized.java?r=3789

y un ejemplo de su uso en:

http://code.google.com/p/migen/source/browse/trunk/java/src/.../ServerBuilderTest.java?r=3789

Los formatos de descripción de la prueba muy bien en Eclipse que es lo que quería ya que esto hace pruebas fallidas mucho más fácil de encontrar! Probablemente voy a perfeccionar y documentar las clases en los próximos días / semanas. Suelta el '?' parte de las direcciones URL si desea que el borde de la sangría. :-)

Para usarlo, todo lo que tiene que hacer es copiar esa clase (GPL v3), y cambiar @RunWith (Parameterized.class) a @RunWith (LabelledParameterized.class) suponiendo que el primer elemento de la lista de parámetros es una etiqueta sensible.

No sé si alguna versiones posteriores de dirección de JUnit este tema, pero incluso si lo hicieran, no se pueden actualizar JUnit ya que todos mis compañeros de desarrolladores tendrían que actualizar también y tenemos prioridades más altas que re-herramientas. Por lo tanto el trabajo en la clase para ser compilable por varias versiones de JUnit.


Nota: hay una cierta reflexión tejemanejes para que se ejecute a través de las diferentes versiones JUnit como se indica anteriormente. La versión específica para JUnit 4.3.1 se puede encontrar aquí y, por JUnit 4.4 y 4.5, aquí .

Respondida el 12/01/2010 a las 21:42
fuente por usuario

votos
2

Hago uso extensivo de importación estática para afirmar y amigos, por lo que es fácil para mí para redefinir la afirmación:

private <T> void assertThat(final T actual, final Matcher<T> expected) {
    Assert.assertThat(editThisToDisplaySomethingForYourDatum, actual, expected);
}

Por ejemplo, se puede añadir un campo "nombre" a su clase de prueba, inicializado en el constructor, y mostrar que el fallo de la prueba. Sólo tiene que pasar en que los primeros elementos de la matriz de parámetros para cada prueba. Esto también ayuda a etiquetar los datos:

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}
    });
}
Respondida el 14/01/2010 a las 18:19
fuente por usuario

votos
13

Con Parameterizedcomo modelo, escribí mi propia prueba personalizada corredor / suite - sólo tomó alrededor de media hora. Es un poco diferente de la de darrenp LabelledParameterizedya que le permite especificar un nombre de forma explícita en lugar de confiar en el primer parámetro de toString().

También no utiliza matrices porque odio matrices. :)

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

Y un ejemplo:

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

}
Respondida el 04/08/2010 a las 10:35
fuente por usuario

votos
6

de junit4.8.2, puede crear su propia clase MyParameterized simplemente copiar la clase parametrizada. cambiar los métodos getName () y testName () en TestClassRunnerForParameters.

Respondida el 04/01/2011 a las 22:34
fuente por usuario

votos
2

Nada de esto estaba trabajando para mí, así que me dieron la fuente para parametrizar y lo modificó crear aa nuevo corredor de prueba. No he tenido que cambiar mucho pero funciona !!!

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;
}
}
Respondida el 24/05/2011 a las 18:11
fuente por usuario

votos
6

También es posible que desee probar JUnitParams: http://code.google.com/p/junitparams/

Respondida el 08/06/2011 a las 15:30
fuente por usuario

votos
0