如何在 JUnit 测试中创建一个可选的 Parameterized.Parameter?
How to make an optional Parameterized.Parameter in JUnit test?
我必须使用 JUnit 测试,该测试具有来自带有注释 @Parameterized.Parameters(name = "{0}")
的集合的自动装配参数,该集合中已经有很多测试。我想加一个参数,但是作为大多数程序员,我是一个很懒惰的人,所以我想引入一个可选参数,可以吗?
@Parameterized.Parameter()
importantParameter;
@Parameterized.Parameter(1)
evenMoreImportantParameter;
@Parameterized.Parameter(2)
businessHandshakeBusinessYes;
@Parameterized.Parameter(3)
meBeingLazyOptionalParameter;
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> data() {
Collection<Object[]> params = new ArrayList<>();
params.add(new Object[]{ "wow", "very", "impressive"});
params.add(new Object[]{ "wow", "much", "beautiful"});
// Where I want to be lazy
params.add(new Object[]{ "this", "is", "sooooo", "better"});
return params;
}
在前面显示的情况下,只有最后一个测试会成功,前 2 个测试将生成以下错误消息
java.lang.Exception: Wrong number of parameters and @Parameter fields. @Parameter fields counted: 4, available parameters: 3.
快速查看 Parameterized.class
和 BlockJUnit4ClassRunnerWithParameters.class
的源代码表明无法指定可选参数。
就个人而言,我会保持所有参数的大小相同,但您始终可以创建单元运行程序,复制 Parameterized.class
并使用 null
.[=17 填充数组至最大大小=]
这是一个 Parameterized
执行填充的运行器示例(JUnit 中原始运行器的副本,但使用了私有方法 allParameters
改编):
public class Parameterized extends Suite {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface Parameters {
String name() default "{index}";
// The max number of parameters
int size();
}
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Target(ElementType.TYPE)
public @interface UseParametersRunnerFactory {
Class<? extends ParametersRunnerFactory> value() default BlockJUnit4ClassRunnerWithParametersFactory.class;
}
private static final ParametersRunnerFactory DEFAULT_FACTORY = new BlockJUnit4ClassRunnerWithParametersFactory();
private static final List<Runner> NO_RUNNERS = Collections.<Runner>emptyList();
private final List<Runner> runners;
private final int size;
public Parameterized(Class<?> klass) throws Throwable {
super(klass, NO_RUNNERS);
ParametersRunnerFactory runnerFactory = getParametersRunnerFactory( klass);
Parameters parameters = getParametersMethod().getAnnotation( Parameters.class);
size = parameters.size();
runners = Collections.unmodifiableList(createRunnersForParameters( allParameters(), parameters.name(), runnerFactory));
}
private ParametersRunnerFactory getParametersRunnerFactory(Class<?> klass)
throws InstantiationException, IllegalAccessException {
UseParametersRunnerFactory annotation = klass
.getAnnotation(UseParametersRunnerFactory.class);
if (annotation == null) {
return DEFAULT_FACTORY;
} else {
Class<? extends ParametersRunnerFactory> factoryClass = annotation.value();
return factoryClass.newInstance();
}
}
@Override
protected List<Runner> getChildren() {
return runners;
}
private TestWithParameters createTestWithNotNormalizedParameters(String pattern, int index, Object parametersOrSingleParameter) {
Object[] parameters= (parametersOrSingleParameter instanceof Object[])
? (Object[]) parametersOrSingleParameter
: new Object[] { parametersOrSingleParameter };
return createTestWithParameters(getTestClass(), pattern, index, parameters);
}
private Iterable<Object> allParameters() throws Throwable {
Object parameters = getParametersMethod().invokeExplosively(null);
if (parameters instanceof Iterable) {
return pad((Iterable<Object>) parameters);
} else if (parameters instanceof Object[]) {
return pad(Arrays.asList((Object[]) parameters));
} else {
throw parametersMethodReturnedWrongType();
}
}
private Iterable<Object> pad(Iterable<Object> parameters) {
List<Object> padded = new ArrayList<>();
for ( Object parameter : parameters ) {
Object[] paddedParams = new Object[size];
Object[] current = (Object[]) parameter;
System.arraycopy( current, 0, paddedParams, 0, current.length );
padded.add( paddedParams );
}
return padded;
}
private FrameworkMethod getParametersMethod() throws Exception {
List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(
Parameters.class);
for (FrameworkMethod each : methods) {
if (each.isStatic() && each.isPublic()) {
return each;
}
}
throw new Exception("No public static parameters method on class " + getTestClass().getName());
}
private List<Runner> createRunnersForParameters(
Iterable<Object> allParameters, String namePattern,
ParametersRunnerFactory runnerFactory)
throws InitializationError,
Exception {
try {
List<TestWithParameters> tests = createTestsForParameters(
allParameters, namePattern);
List<Runner> runners = new ArrayList<Runner>();
for (TestWithParameters test : tests) {
runners.add(runnerFactory
.createRunnerForTestWithParameters(test));
}
return runners;
} catch (ClassCastException e) {
throw parametersMethodReturnedWrongType();
}
}
private List<TestWithParameters> createTestsForParameters(
Iterable<Object> allParameters, String namePattern)
throws Exception {
int i = 0;
List<TestWithParameters> children = new ArrayList<TestWithParameters>();
for (Object parametersOfSingleTest : allParameters) {
children.add(createTestWithNotNormalizedParameters(namePattern,
i++, parametersOfSingleTest));
}
return children;
}
private Exception parametersMethodReturnedWrongType() throws Exception {
String className = getTestClass().getName();
String methodName = getParametersMethod().getName();
String message = MessageFormat.format( "{0}.{1}() must return an Iterable of arrays.", className, methodName);
return new Exception(message);
}
private static TestWithParameters createTestWithParameters(
TestClass testClass, String pattern, int index, Object[] parameters) {
String finalPattern = pattern.replaceAll("\{index\}", Integer.toString(index));
String name = MessageFormat.format(finalPattern, parameters);
return new TestWithParameters("[" + name + "]", testClass, Arrays.asList(parameters));
}
}
我必须使用 JUnit 测试,该测试具有来自带有注释 @Parameterized.Parameters(name = "{0}")
的集合的自动装配参数,该集合中已经有很多测试。我想加一个参数,但是作为大多数程序员,我是一个很懒惰的人,所以我想引入一个可选参数,可以吗?
@Parameterized.Parameter()
importantParameter;
@Parameterized.Parameter(1)
evenMoreImportantParameter;
@Parameterized.Parameter(2)
businessHandshakeBusinessYes;
@Parameterized.Parameter(3)
meBeingLazyOptionalParameter;
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> data() {
Collection<Object[]> params = new ArrayList<>();
params.add(new Object[]{ "wow", "very", "impressive"});
params.add(new Object[]{ "wow", "much", "beautiful"});
// Where I want to be lazy
params.add(new Object[]{ "this", "is", "sooooo", "better"});
return params;
}
在前面显示的情况下,只有最后一个测试会成功,前 2 个测试将生成以下错误消息
java.lang.Exception: Wrong number of parameters and @Parameter fields. @Parameter fields counted: 4, available parameters: 3.
快速查看 Parameterized.class
和 BlockJUnit4ClassRunnerWithParameters.class
的源代码表明无法指定可选参数。
就个人而言,我会保持所有参数的大小相同,但您始终可以创建单元运行程序,复制 Parameterized.class
并使用 null
.[=17 填充数组至最大大小=]
这是一个 Parameterized
执行填充的运行器示例(JUnit 中原始运行器的副本,但使用了私有方法 allParameters
改编):
public class Parameterized extends Suite {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface Parameters {
String name() default "{index}";
// The max number of parameters
int size();
}
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Target(ElementType.TYPE)
public @interface UseParametersRunnerFactory {
Class<? extends ParametersRunnerFactory> value() default BlockJUnit4ClassRunnerWithParametersFactory.class;
}
private static final ParametersRunnerFactory DEFAULT_FACTORY = new BlockJUnit4ClassRunnerWithParametersFactory();
private static final List<Runner> NO_RUNNERS = Collections.<Runner>emptyList();
private final List<Runner> runners;
private final int size;
public Parameterized(Class<?> klass) throws Throwable {
super(klass, NO_RUNNERS);
ParametersRunnerFactory runnerFactory = getParametersRunnerFactory( klass);
Parameters parameters = getParametersMethod().getAnnotation( Parameters.class);
size = parameters.size();
runners = Collections.unmodifiableList(createRunnersForParameters( allParameters(), parameters.name(), runnerFactory));
}
private ParametersRunnerFactory getParametersRunnerFactory(Class<?> klass)
throws InstantiationException, IllegalAccessException {
UseParametersRunnerFactory annotation = klass
.getAnnotation(UseParametersRunnerFactory.class);
if (annotation == null) {
return DEFAULT_FACTORY;
} else {
Class<? extends ParametersRunnerFactory> factoryClass = annotation.value();
return factoryClass.newInstance();
}
}
@Override
protected List<Runner> getChildren() {
return runners;
}
private TestWithParameters createTestWithNotNormalizedParameters(String pattern, int index, Object parametersOrSingleParameter) {
Object[] parameters= (parametersOrSingleParameter instanceof Object[])
? (Object[]) parametersOrSingleParameter
: new Object[] { parametersOrSingleParameter };
return createTestWithParameters(getTestClass(), pattern, index, parameters);
}
private Iterable<Object> allParameters() throws Throwable {
Object parameters = getParametersMethod().invokeExplosively(null);
if (parameters instanceof Iterable) {
return pad((Iterable<Object>) parameters);
} else if (parameters instanceof Object[]) {
return pad(Arrays.asList((Object[]) parameters));
} else {
throw parametersMethodReturnedWrongType();
}
}
private Iterable<Object> pad(Iterable<Object> parameters) {
List<Object> padded = new ArrayList<>();
for ( Object parameter : parameters ) {
Object[] paddedParams = new Object[size];
Object[] current = (Object[]) parameter;
System.arraycopy( current, 0, paddedParams, 0, current.length );
padded.add( paddedParams );
}
return padded;
}
private FrameworkMethod getParametersMethod() throws Exception {
List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(
Parameters.class);
for (FrameworkMethod each : methods) {
if (each.isStatic() && each.isPublic()) {
return each;
}
}
throw new Exception("No public static parameters method on class " + getTestClass().getName());
}
private List<Runner> createRunnersForParameters(
Iterable<Object> allParameters, String namePattern,
ParametersRunnerFactory runnerFactory)
throws InitializationError,
Exception {
try {
List<TestWithParameters> tests = createTestsForParameters(
allParameters, namePattern);
List<Runner> runners = new ArrayList<Runner>();
for (TestWithParameters test : tests) {
runners.add(runnerFactory
.createRunnerForTestWithParameters(test));
}
return runners;
} catch (ClassCastException e) {
throw parametersMethodReturnedWrongType();
}
}
private List<TestWithParameters> createTestsForParameters(
Iterable<Object> allParameters, String namePattern)
throws Exception {
int i = 0;
List<TestWithParameters> children = new ArrayList<TestWithParameters>();
for (Object parametersOfSingleTest : allParameters) {
children.add(createTestWithNotNormalizedParameters(namePattern,
i++, parametersOfSingleTest));
}
return children;
}
private Exception parametersMethodReturnedWrongType() throws Exception {
String className = getTestClass().getName();
String methodName = getParametersMethod().getName();
String message = MessageFormat.format( "{0}.{1}() must return an Iterable of arrays.", className, methodName);
return new Exception(message);
}
private static TestWithParameters createTestWithParameters(
TestClass testClass, String pattern, int index, Object[] parameters) {
String finalPattern = pattern.replaceAll("\{index\}", Integer.toString(index));
String name = MessageFormat.format(finalPattern, parameters);
return new TestWithParameters("[" + name + "]", testClass, Arrays.asList(parameters));
}
}