michael nesterenko
michael nesterenko

Reputation: 14439

wrong junit test names

I try to write own junit runner and currently I am stuck at returning proper test description.

public class ParameterizedWrapper extends Suite {
    private List<Runner> fRunners;

    /**
     * @throws Throwable 
     * 
     */
    public ParameterizedWrapper(final Class<?> clazz) throws Throwable {
        super(clazz, Collections.<Runner>emptyList());
        fRunners = constructRunners(getParametersMethod());
    }

    protected List<Runner> constructRunners(final FrameworkMethod method) throws Exception, Throwable {
        @SuppressWarnings("unchecked")
        Iterable<Object[]> parameters = (Iterable<Object[]>) getParametersMethod().invokeExplosively(null);
        ArrayList<Runner> runners = new ArrayList<Runner>();
        int index = 0;
        for (Object[] parameter : parameters) {
            Class<?> testClass = getTestClass().getJavaClass();
            WrappedRunner wrappedRunner = testClass.getAnnotation(WrappedRunner.class);
            Runner runner = wrappedRunner.value().getConstructor(Class.class).newInstance(getTestClass().getJavaClass());
            runners.add(new WrappingRunner(runner, parameter, testClass, index++));
        }
        return runners;
    }

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

    @Override
    protected List<Runner> getChildren() {
        return fRunners;
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    public static @interface WrappedRunner {
        Class<? extends Runner> value();
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public static @interface ParameterSetter {
    }

}

class WrappingRunner extends Runner {
    private Runner wrappedRunner;

    private Object[] parameters;

    private Class<?> testClass;

    private int testPosition;

    public WrappingRunner(final Runner runner, final Object[] params, final Class<?> clazz, final int position) {
        wrappedRunner = runner;
        parameters = params;
        testClass = clazz;
        testPosition = position;
    }

    @Override
    public Description getDescription() {
        Description originalDescription = wrappedRunner.getDescription();
        Description newDescription = Description.createSuiteDescription(nameFor(""), new Annotation[0]);
        for (Description child : originalDescription.getChildren()) {
            newDescription.addChild(decorateChildDescription(child));
        }

        return newDescription;
    }

    private String nameFor(String name) {
        return String.format("%1$s[%2$s]", name, testPosition);
    }

    protected Description decorateChildDescription(final Description originalChildDescription) {
        Description d = Description.createTestDescription(originalChildDescription.getTestClass(),
                nameFor(originalChildDescription.getMethodName()),
                originalChildDescription.getAnnotations().toArray(new Annotation[0]));
        return d;
    }

    @Override
    public void run(final RunNotifier notifier) {
        try {
            ParameterStorage.storeParameters(testClass, parameters);
            wrappedRunner.run(notifier);
        } finally {
            ParameterStorage.clearParameters(testClass);
        }
    }
}

I have some test class to check if runner works. Runner works fine except tests are named weirdly. In eclipse it displays all tests and adds unrooted tests category

enter image description here

and surefire does not use my naming at all:

enter image description here

I compared description objects generated in my runner and in Parameterized runner, there seems to be no difference.

Upvotes: 0

Views: 315

Answers (2)

NamshubWriter
NamshubWriter

Reputation: 24286

It's a bit ugly, but it's safer to pass the list of child runners to the parent constructor:

public ParameterizedWrapper(final Class<?> clazz) throws Throwable {
  super(clazz, constructRunners(getParametersMethod());
}

private static List<Runner> constructRunners(final FrameworkMethod method)
    throws Throwable {
  ...

You shouldn't need to override Suite.getChildren()

Upvotes: 1

michael nesterenko
michael nesterenko

Reputation: 14439

I have checked a bit more and found that description generated by my runner is ok. But that does not matter as it is inconsistent with description used during actual test execution. That is why eclipse shows entries as not executed and that is why surefire does not show my names.

Currently I think to use my own notifier to catch test start point and replace configuration at that point.

If someone has a better solution I would like to know about it :).

Upvotes: 0

Related Questions