如何将多维数组作为JUnit测试的参数集合返回



我对Java还很陌生,当然我还不太了解。好吧,抛开免责声明不谈,这是我的故事:

我在一个XML文件中有一个很大的视频文件名和称为引用ID的互补字符串列表。XML如下所示:

<testdata>
<testcase displayName="video1" refId="vid1xxyyzz" />
<testcase displayName="video2" refId="vid2aabbcc" />
.
.
<testcase displayName="video499" refId="vid499ffoooo" />
</testdata>

我已经使用XMLBeans将XML模式转换为一个类,并且可以使用下面介绍的方法将数据导入到几个数组中:http://docs.oracle.com/javase/tutorial/reflect/special/arraySetGet.html

// File import:
File refIdFile = new File("C:testdata.xml");
DisplayNameReferenceIdDoc = DisplayNameReferenceIdDocument.Factory.parse(refIdFile);
displayNameReferenceId = DisplayNameReferenceIdDoc.getDisplayNameReferenceId();
tests = displayNameReferenceId.getTestcaseArray();
// Multi-dimensional array get/set:
matrix = Array.newInstance(String.class, 2, tests.length);
Object row0 = Array.get(matrix, 0);
Object row1 = Array.get(matrix, 1);
for (int i = 0; i < tests.length; i++){
displayName = tests[i].getDisplayName();
refId = tests[i].getRefId();
Array.set(row0, i, displayName);
Array.set(row1, i, refId);
}

这一切都发生在我的测试类中的@Parameterized方法中,它必须返回一个集合。这是整件事,缩小:

@RunWith(Parameterized.class)
public class ValidateDisplayNameReferenceIdTest {
static DisplayNameReferenceIdDocument DisplayNameReferenceIdDoc;
static DisplayNameReferenceId displayNameReferenceId;
static DisplayNameReferenceId.Test[] tests;
static String displayName;
static String refId;
static Object matrix;
@Parameterized.Parameters(name="{index}: {0}")
public static Collection<Object> getTestParameters() throws IOException, XmlException {
File refIdFile = new File("C:testdata.xml");
DisplayNameReferenceIdDoc = DisplayNameReferenceIdDocument.Factory.parse(refIdFile);
displayNameReferenceId = DisplayNameReferenceIdDoc.getDisplayNameReferenceId();
tests = displayNameReferenceId.getTestArray();
matrix = Array.newInstance(String.class, 2, tests.length);
Object row0 = Array.get(matrix, 0);
Object row1 = Array.get(matrix, 1);
for (int i = 0; i < tests.length; i++){
displayName = tests[i].getDisplayName();
refId = tests[i].getRefId();
Array.set(row0, i, displayName);
Array.set(row1, i, refId);
}
System.out.println("tweet");
return Arrays.asList(matrix);  // NOT SURE ABOUT THIS!
}

private String displayNameInput;
private String refIdExpected;
public ValidateDisplayNameReferenceIdTest(String input, String expected ) {
displayNameInput = input;
refIdExpected = expected;
}
@Test
public void test() throws IOException {
// send the API URL with 'displayNameInput', validate result for 'refIdExpected'
URLConnection connection = new URL(url1 + displayNameInput + url2 + token).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
StringWriter writer = new StringWriter();
IOUtils.copy(response, writer);
String responseString = writer.toString();
System.out.println(responseString);
//Here goes something like assert(response.contains(refIdExpected));
}
}

当我按原样运行时,我得到java.lang.IllegalArgumentException: argument type mismatch at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

我想我可能会使数据结构过于复杂,但现在它是以这种方式构建的,并且似乎成功地引入了数据元素,我不知道如何重建。有人看到我做错了什么吗?

这是一个血腥的例外:

java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at org.junit.runners.Parameterized$TestClassRunnerForParameters.createTestUsingConstructorInjection(Parameterized.java:186)
at org.junit.runners.Parameterized$TestClassRunnerForParameters.createTest(Parameterized.java:181)
at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:244)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:241)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
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.junit.runners.Suite.runChild(Suite.java:127)
at org.junit.runners.Suite.runChild(Suite.java:26)
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.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:202)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:65)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

Arrays.asList的定义如下:

static <T> List<T> asList(T... a)

它采用可变长度的参数列表。当你调用这样的方法时,程序实际上会构建一个数组来传递给方法--,除非你用一个参数调用它,并且该参数已经是一个数组。在这种情况下,它将传递您已经构建的数组。

这里的问题是,如果将matrix定义为Object,编译器将不会将其视为数组。因此,它构造了一个以matrix为元素的单元素数组。最终,这会打乱JUnit代码。

要使用asList,您需要确保参数具有实际的数组类型(在编译时)。然而,我不确定什么会起作用。你想要这样的东西:

return Arrays.asList((Object[][])matrix);

但我有一种感觉,这种类型的演员阵容在运行时会失败。您可能需要将matrix声明为

Object[][] matrix;

然后代替

matrix = Array.newInstance(String.class, 2, tests.length);

比如

matrix = new Object[2][tests.length];

(无论如何,我认为在这里使用Array.newInstance没有任何好处,而不是只使用常规的new。)

我认为问题在于JUnit@Parameters方法需要返回一个Object数组列表,而您正在向它传递一个String数组列表。由于二维数组基本上只是数组的数组,因此将二维String数组(String[][])传递到arrays中。asList()返回一个List<String[]>,一个String数组列表。

不过,当您设置它时,它确实很容易修复,只需将传递给Array构造函数的String.class参数更改为Object.class,就应该有功能测试。

由于我无法编辑@ajb的答案和随后的评论,我将把最终有效的内容放在它自己的答案中。

正如建议的那样,我尝试将matrix声明为Object[][],但保留了表达式的其余部分和for循环,但仍然不起作用。正是newInstance设置数组的方法给我带来了麻烦。最后,我去掉了它,并用这个替换了相关的块:

//Same as before from XMLBeans methods:
DisplayNameReferenceIdDoc = DisplayNameReferenceIdDocument.Factory.parse(refIdFile);
displayNameReferenceId = DisplayNameReferenceIdDoc.getDisplayNameReferenceId();
tests = displayNameReferenceId.getTestcaseArray();
//new, simpler Object setup strategy:
int i;
Object[][] matrix = new Object[tests.length][2];
for (i = 0; i < tests.length; i++) {
matrix[i][0] = tests[i].getDisplayName();
matrix[i][1] = tests[i].getRefId();
};
return Arrays.asList(matrix);

@Parameterized测试运行程序按预期将值对发送到我的测试构造函数,该类开始按照我的@Test块的指示愉快地进行web服务调用。

在一个完美的世界里,XMLBeans包本身会为复杂的行项目发回多维数组,这样用户就不必进行这种争论了。

最新更新