unitarias unitaria tutorial tipos test software pruebas prueba libre framework espaƱol empaqueta ejemplo cuyo con java eclipse unit-testing junit parameterized-unit-test

java - unitaria - Prueba parametrizada con un nombre en Eclipse Testrunner



test en java (5)

Cuando ejecuta un JUnit 4 ParameterizedTest con el Eclipse TestRunner, la representación gráfica es bastante tonta: para cada prueba tiene un nodo llamado [0] , [1] , etc. ¿Es posible dar las pruebas [0] , [1] , etc. nombres explícitos? Implementar un método toString para las pruebas no parece ayudar.

(Esta es una pregunta de seguimiento para la prueba JUnit con un número dinámico de pruebas ).


Creo que no hay nada incorporado en jUnit 4 para hacer esto.

Implementé una solución. Construí mi propia clase Parameterized basada en la existente:

public class MyParameterized extends TestClassRunner { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public static @interface Parameters { } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public static @interface Name { } public static Collection<Object[]> eachOne(Object... params) { List<Object[]> results = new ArrayList<Object[]>(); for (Object param : params) results.add(new Object[] { param }); return results; } // TODO: single-class this extension private static class TestClassRunnerForParameters extends TestClassMethodsRunner { private final Object[] fParameters; private final Class<?> fTestClass; private Object instance; private final int fParameterSetNumber; private final Constructor<?> fConstructor; private TestClassRunnerForParameters(Class<?> klass, Object[] parameters, int i) throws Exception { super(klass); fTestClass = klass; fParameters = parameters; fParameterSetNumber = i; fConstructor = getOnlyConstructor(); instance = fConstructor.newInstance(fParameters); } @Override protected Object createTest() throws Exception { return instance; } @Override protected String getName() { String name = null; try { Method m = getNameMethod(); if (m != null) name = (String) m.invoke(instance); } catch (Exception e) { } return String.format("[%s]", (name == null ? fParameterSetNumber : name)); } @Override protected String testName(final Method method) { String name = null; try { Method m = getNameMethod(); if (m != null) name = (String) m.invoke(instance); } catch (Exception e) { } return String.format("%s[%s]", method.getName(), (name == null ? fParameterSetNumber : name)); } private Constructor<?> getOnlyConstructor() { Constructor<?>[] constructors = getTestClass().getConstructors(); assertEquals(1, constructors.length); return constructors[0]; } private Method getNameMethod() throws Exception { for (Method each : fTestClass.getMethods()) { if (Modifier.isPublic((each.getModifiers()))) { Annotation[] annotations = each.getAnnotations(); for (Annotation annotation : annotations) { if (annotation.annotationType() == Name.class) { if (each.getReturnType().equals(String.class)) return each; else throw new Exception("Name annotated method doesn''t return an object of type String."); } } } } return null; } } // TODO: I think this now eagerly reads parameters, which was never the // point. public static class RunAllParameterMethods extends CompositeRunner { private final Class<?> fKlass; public RunAllParameterMethods(Class<?> klass) throws Exception { super(klass.getName()); fKlass = klass; int i = 0; for (final Object each : getParametersList()) { if (each instanceof Object[]) super.add(new TestClassRunnerForParameters(klass, (Object[]) each, i++)); else throw new Exception(String.format("%s.%s() must return a Collection of arrays.", fKlass.getName(), getParametersMethod().getName())); } } private Collection<?> getParametersList() throws IllegalAccessException, InvocationTargetException, Exception { return (Collection<?>) getParametersMethod().invoke(null); } private Method getParametersMethod() throws Exception { for (Method each : fKlass.getMethods()) { if (Modifier.isStatic(each.getModifiers())) { Annotation[] annotations = each.getAnnotations(); for (Annotation annotation : annotations) { if (annotation.annotationType() == Parameters.class) return each; } } } throw new Exception("No public static parameters method on class " + getName()); } } public MyParameterized(final Class<?> klass) throws Exception { super(klass, new RunAllParameterMethods(klass)); } @Override protected void validate(MethodValidator methodValidator) { methodValidator.validateStaticMethods(); methodValidator.validateInstanceMethods(); } }

Para ser utilizado como:

@RunWith(MyParameterized.class) public class ParameterizedTest { private File file; public ParameterizedTest(File file) { this.file = file; } @Test public void test1() throws Exception {} @Test public void test2() throws Exception {} @Name public String getName() { return "coolFile:" + file.getName(); } @Parameters public static Collection<Object[]> data() { // load the files as you want Object[] fileArg1 = new Object[] { new File("path1") }; Object[] fileArg2 = new Object[] { new File("path2") }; Collection<Object[]> data = new ArrayList<Object[]>(); data.add(fileArg1); data.add(fileArg2); return data; } }

Esto implica que instanciar la clase de prueba antes. Espero que esto no cause ningún error ... Creo que debería probar las pruebas :)


No hay indicios de que esta característica esté o vaya a implementarse. Pediría esta característica porque es bueno tenerla.


JUnit4 ahora permite especificar un atributo de nombre para la anotación parametrizada, de modo que se puede especificar un patrón de nomenclatura a partir de los métodos index y toString de los argumentos. P.ej:

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


Una solución sin código, aunque no tan cómoda, es pasar suficiente información de contexto para identificar la prueba en mensajes de afirmación. Todavía verá que testYY [0] falló, pero el mensaje detallado le dice cuál fue.

assertEquals("Not the expected decision for the senator " + this.currentSenatorName + " and the law " + this.votedLaw, expectedVote, actualVote);


Si usa la biblioteca JUnitParams (como he descrito aquí ), las pruebas parametrizadas tendrán sus parámetros codificados como sus propios nombres de prueba predeterminados.

Además, puede ver en sus muestras que JUnitParams también le permite tener un nombre de prueba personalizado usando @TestCaseName :

@Test @Parameters({ "1,1", "2,2", "3,6" }) @TestCaseName("factorial({0}) = {1}") public void custom_names_for_test_case(int argument, int result) { }

@Test @Parameters({ "value1, value2", "value3, value4" }) @TestCaseName("[{index}] {method}: {params}") public void predefined_macro_for_test_case_name(String param1, String param2) { }