简体   繁体   English

如何使用带有可变参数构造函数的 JUnit 参数化运行器?

[英]How do I use a JUnit Parameterized runner with a varargs constructor?

I wrote a mockup example to illustrate this without exposing anything confidential.我写了一个模型示例来说明这一点,而不会暴露任何机密信息。 It's a "dummy" example which does nothing, but the problem occurs in the test initialiser.这是一个什么都不做的“虚拟”示例,但问题出现在测试初始化​​程序中。

@RunWith(Parameterized.class)
public class ExampleParamTest
{
 int ordinal;
 List<String> strings;

 public ExampleParamTest(int ordinal, String... strings)
 {
  this.ordinal = ordinal;
  if (strings.length == 0)
  {
   this.strings = null;
  }
  else
  {
   this.strings = Arrays.asList(strings);
  }
 }

 @Parameters
 public static Collection<Object[]> data() {
  return Arrays.asList(new Object[][] {
    {0, "hello", "goodbye"},
    {1, "farewell"}
  });
 }

 @Test
 public void doTest() {
  Assert.assertTrue(true);
 }
}

Basically I have a test constructor which accepts multiple arguments for a local list variable and I want to populate this through an array initialiser.基本上我有一个测试构造函数,它接受一个本地列表变量的多个参数,我想通过一个数组初始化器来填充它。 The test method will handle the local list variable correctly - I have removed this logic to simplify the test.测试方法将正确处理本地列表变量 - 我已删除此逻辑以简化测试。

When I write this, my IDE has no complaints about syntax and the test class builds without any compile errors.当我写这篇文章时,我的 IDE 对语法没有任何抱怨,并且测试类的构建没有任何编译错误。 However when I run it, I get:但是,当我运行它时,我得到:

doTest[0]:
java.lang.IllegalArgumentException: wrong number of arguments
  at java.lang.reflect.Constructor.newInstance(Unknown Source)
doTest[1]:
java.lang.IllegalArgumentException: argument type mismatch
  at java.lang.reflect.Constructor.newInstance(Unknown Source)

What exactly has gone wrong here, and how do I correctly use this pattern?这里到底出了什么问题,我该如何正确使用这种模式?

Can't test it right now but I guess, if you invoke a method or a constructor with variable arguments, you have to invoke it with an array instead of a variable list of values.现在无法对其进行测试,但我想,如果您使用可变参数调用方法或构造函数,则必须使用数组而不是变量值列表来调用它。

If I'm right, then this should work:如果我是对的,那么这应该有效:

@Parameters
 public static Collection<Object[]> data() {
  return Arrays.asList(new Object[][] {
    {0, new String[]{"hello", "goodbye"}},
    {1, new String[]{"farewell"}}
  });
 }

Some explanation一些解释

On source code level, we can write在源代码级别,我们可以写

test = ExampleParamTest(0, "one", "two");

The compiler will convert this to an array of Strings.编译器会将其转换为字符串数组。 JUnit uses the reflection and invocation API, and from this perspective, the constructors signature is JUnit 使用反射和调用 API,从这个角度来看,构造函数签名是

public ExampleParamTest(int i, String[] strings);

So to invoke the constructor - and that's what JUnit is doing internally - you have to pass an integer and a String array.所以要调用构造函数——这就是 JUnit 在内部所做的——你必须传递一个整数和一个字符串数组。

The workaround given by @marcphillip in this JUnit feature request works great for now: @marcphillip 在此JUnit 功能请求中给出的解决方法现在效果很好:

@ParameterizedTest
@CsvSource({"1,a", "1,a,b,c"})
void testAbc(int arg1, @AggregateWith(VarargsAggregator.class) String... elements) {
    System.out.println(Arrays.toString(elements));
}

static class VarargsAggregator implements ArgumentsAggregator {
    @Override
    public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context) throws ArgumentsAggregationException {
        Class<?> parameterType = context.getParameter().getType();
        Preconditions.condition(parameterType.isArray(), () -> "must be an array type, but was " + parameterType);
        Class<?> componentType = parameterType.getComponentType();
        return IntStream.range(context.getIndex(), accessor.size())
                .mapToObj(index -> accessor.get(index, componentType))
                .toArray(size -> (Object[]) Array.newInstance(componentType, size));
    }
}

Update: I added this tweak to give an empty array when there is nothing provided after the last comma:更新:当最后一个逗号后没有提供任何内容时,我添加了这个调整以提供一个空数组:

        if (result.length == 1 && result[0] == null) {
            return Array.newInstance(componentType, 0);
        }
        return result;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM