2008-12-22 8 views

Antwort

3

JUnit4 jetzt allows specifying a name attribute auf die Parameterized Anmerkung, so dass Sie ein Benennungsmuster aus dem Index und toString Methoden der Argumente angeben. Z.B .:

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

Ich denke, nichts in in jUnit 4 gebaut gibt es, dies zu tun.

Ich habe eine Lösung implementiert. Ich habe meine eigene Parameterized Klasse auf der Grundlage der bestehenden gebaut:

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

} 

Um dergleichen verwendet werden:

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

Dies bedeutet, dass ich die Testklasse früher instanziiert. Ich hoffe, dass dies keine Fehler verursacht ... Ich denke, ich sollte die Tests testen :)

+1

FYI: Die Antwort für JUnit 4.0 noch richtig ist, Aber glücklicherweise ist das Hinzufügen von benutzerdefinierten Namen in JUnit 4.11 möglich. Siehe http://stackoverflow.com/a/10143872/103814 – NobodyMan

0

Es gibt keinen Hinweis, dass diese Funktion implementiert ist oder wird. Ich würde diese Funktion anfordern, weil es nett ist.

+1

Nicht mehr wahr. –

2

Eine codefreie, aber nicht so komfortable Lösung besteht darin, genügend Kontextinformationen zu übergeben, um den Test in Assert-Nachrichten zu identifizieren. Sie werden immer noch sehen, nur testXY [0] fehlgeschlagen, aber die detaillierte Nachricht sagt Ihnen, welche war das.

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

Wenn Sie JUnitParams library (wie ich described here haben), werden die parametrisierte Tests ihre Zeichenfolgeparameter als ihre eigenen Standardtest Namen haben.

Außerdem you can see in their samples, dass JUnitParams kann Sie auch einen benutzerdefinierten Testnamen @TestCaseName unter Verwendung haben:

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