2014-02-05 7 views
5

diese Testklasse Betrachten wir mit JUnit Arbeits 4 und JUnitParams:JUnitParams nicht mit String-Array arbeitet

import static junitparams.JUnitParamsRunner.$; 
import junitparams.JUnitParamsRunner; 
import junitparams.Parameters; 

import org.junit.Test; 
import org.junit.runner.RunWith; 

@RunWith(JUnitParamsRunner.class) 
public class JUnitParamsExample { 

    private int[] getIntArray() { 
     int array[] = new int[2]; 
     array[0] = 1; 
     array[1] = 2; 
     return array; 
    } 

    public Object getInts() { 
     return $($(getIntArray())); 
    } 

    @Parameters(method = "getInts") 
    @Test 
    public void testIntArray(int... values) { 
     // 
    } 

    private String[] getStringArray() { 
     String array[] = new String[2]; 
     array[0] = "a"; 
     array[1] = "b"; 
     return array; 
    } 

    public Object getStrings() { 
     return $($(getStringArray())); 
    } 

    @Parameters(method = "getStrings") 
    @Test 
    public void testStringArray(String... values) { 
     // 
    } 
} 

Das Prüfverfahren testIntArray fein läuft, während testStringArray nicht. Der Fehlerausgang ist:

java.lang.IllegalArgumentException: Cannot parse parameters. Did you use , as column separator? a 
    at junitparams.internal.InvokeParameterisedMethod.castParamsFromString(InvokeParameterisedMethod.java:51) 
    at junitparams.internal.InvokeParameterisedMethod.<init>(InvokeParameterisedMethod.java:35) 
    at junitparams.internal.ParameterisedTestClassRunner.buildMethodInvoker(ParameterisedTestClassRunner.java:121) 
    at junitparams.internal.ParameterisedTestClassRunner.parameterisedMethodInvoker(ParameterisedTestClassRunner.java:115) 
    at junitparams.JUnitParamsRunner.methodInvoker(JUnitParamsRunner.java:425) 
    at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:251) 
    at junitparams.JUnitParamsRunner.runChild(JUnitParamsRunner.java:405) 
    at junitparams.JUnitParamsRunner.runChild(JUnitParamsRunner.java:383) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 
Caused by: java.lang.IllegalArgumentException: Parameter type cannot be handled! Only primitive types and Strings can be used. 
    at junitparams.internal.InvokeParameterisedMethod.castParameterDirectly(InvokeParameterisedMethod.java:171) 
    at junitparams.internal.InvokeParameterisedMethod.castAllParametersToProperTypes(InvokeParameterisedMethod.java:122) 
    at junitparams.internal.InvokeParameterisedMethod.castParamsUsingConverters(InvokeParameterisedMethod.java:101) 
    at junitparams.internal.InvokeParameterisedMethod.castParamsFromString(InvokeParameterisedMethod.java:49) 

Ich frage mich, warum und int Werke Array und ein String-Array nicht. Gibt es eine Möglichkeit, ein String-Array an eine Varargs-Testmethode mit Junitparams zu übergeben?

EDIT: so etwas wie das, was ich möchte, ist schreiben:

public Object getStrings() { 
     return $($("Hello", "world"), 
       $("Me", "You"), 
       $("Dog", "Cat")); 
} 

, so dass alle inneren $ -Einträge zum varargs Argumente übergeben werden.

Antwort

5

Okay, im Grunde sieht es so aus, als wäre es ein Bug in JUnitParams. Nach dem Anwenden der Korrektur in der ursprünglichen Antwort unten "entpackt" die Bibliothek immer noch die String[], wenn wir es nicht wollen - angesichts der Menge des bedingten Umbrechens und Entpackens in der Quelle scheint es, dass der Autor entweder versucht Sie sind zu schlau für ihr eigenes Wohl, oder sie wissen nicht wirklich, was sie zu einem bestimmten Zeitpunkt erwarten. Der Unterschied tritt in safelyCastParamsToArray, wo im int[] Fall ist es ein int[] übergeben wird und wickelt es in einem Object[], während in den String[] Fällen ein String[] übergeben wird, die nicht gewickelt ist, weil es bereits zu Object[] gegossen werden kann.

Sie können es, indem sie Ihre Methode eine zurückkehren funktioniert doppelt gewickelt Array, wie folgt aus:

return $((Object)$((Object)getStringArray())); 

Oder einfach:

return new Object[] { new Object[] { getStringArray() } }; 

Die int[] Version benötigt nur eine einzelne Ebene der Verpackung jedoch, so können Sie einfach verwenden:

return $(getIntArray()); 

statt der "versuchte doppelte Umhüllung, die von Varargs vereitelt wird" in Ihrem aktuellen Code.

Persönlich bin ich etwas vorsichtig bei all dies - es hat eine deutlich „schwarze Magie, basteln, bis es funktioniert“ Gefühl, das nicht in sauberen APIs sein neigt ...


Ursprüngliche Antwort

ich glaube, das Problem ist, dass ein String[] Array ist bereits ein Object[], so dass Sie enden nicht mit ihm in den Weg gewickelt ist, dass Sie es wollen - varargs wie das das Argument behandelt ganzes Array und nicht ein Element des Arrays.Sie können dieses Problem beheben ziemlich leicht aber:

public Object getStrings() { 
    Object array = getStringArray(); 
    return $(array); 
} 

Oder benutzen Sie einfach eine Besetzung:

public Object getStrings() { 
    return $((Object) getStringArray()); 
} 

Oder nur die $ Methode in diesem Fall ignorieren:

public Object getStrings() { 
    return new Object[] { getStringArray() }; 
} 

(ich bezweifle sehr, Sie brauchen $($(...)) in entweder Fall - Sie versuchen nur, ein Array von Arrays zu machen, oder? Also nur eine einzige Ebene von wra pping ist erforderlich, und Sie sind nur immer eine einzige Ebene ohnehin Einwickeln, für genau den gleichen Grund, dass Ihr Original-Code nicht mit dem String-Array nicht funktionierte.)

+0

Die varargs sollten das Argument als das gesamte Array behandeln, da die zu testende Methode auch a verwendet varargs Argument. Ich möchte dieses Array nur an die Testmethode übergeben. Mit Ihrem Vorschlag gibt JUnit diesen Fehler aus: java.lang.IllegalStateException: Beim Versuch, ein Objekt der Klassenklasse [Ljava.lang.String; Konnte keinen Konstruktor mit Argumenten finden, die (typenmäßig) denen in Parametern entsprechen. – Juergen

+0

@Juergen: Die Tatsache, dass es ein Varargs-Parameter in der Test-Methode ist, ist fast sicher unbemerkt für den Test-Runner - es nur als String-Array, die ich denke, es hat Probleme beim Erstellen ... –

+0

Ich kann es funktionieren mit der Übergabe einer String-Liste an die Testmethode und der anschließenden Umwandlung in ein Array, das wiederum an die zu testende Methode übergeben wird. Aber es sieht hässlich und "überhastet" aus ... – Juergen

0

vielleicht zohhak Bibliothek Ihnen helfen kann. Es basiert auf Junit Params. Sie können nur Parameter in Annotation als String angeben, aber Sie können auf einfache Weise eigene benutzerdefinierte Parser für diese Strings erstellen.