并行化+参数化线程,每个线程具有随机执行顺序

时间:2015-02-26 15:55:55

标签: java junit

我有一个与参数并行运行测试的课程。但是为了检查并发性问题,我想以随机顺序执行测试。 例如。 test1 - test2 - test3在第一个线程上,test2 - test1 - test3在第二个线程上。 (我认为你明白了)

这是我目前正在使用的代码,我已经使用BlockJUnit4ClassRunnerWithParameters找到了一些示例,但是将Parameterized更改为BlockJUnit4ClassRunnerWithParameters显然不适合我。

因此我的问题是:如何让每个线程以随机顺序执行测试?

希望你们能给我一些指示......

public class Parallelized extends Parameterized
{

    private static class ThreadPoolScheduler implements RunnerScheduler
    {
        private ExecutorService executor; 

        public ThreadPoolScheduler()
        {
            String threads = System.getProperty("junit.parallel.threads", "16");
            int numThreads = Integer.parseInt(threads);
            executor = Executors.newFixedThreadPool(numThreads);
        }

        @Override
        public void finished()
        {
            executor.shutdown();
            try
            {
                executor.awaitTermination(10, TimeUnit.MINUTES);
            }
            catch (InterruptedException exc)
            {
                throw new RuntimeException(exc);
            }
        }

        @Override
        public void schedule(Runnable childStatement)
        {
            executor.submit(childStatement);
        }
    }

    public Parallelized(Class klass) throws Throwable
    {
        super(klass);
        setScheduler(new ThreadPoolScheduler());
    }
}

2 个答案:

答案 0 :(得分:1)

好的,我找到了一个相当简单的解决方案:

您需要的只是一个ParametersRunnerFactory,它可以创建BlockJUnit4ClassRunnerWithParameters类型的Runners。 要为每个跑步者随机化测试顺序,您只需覆盖computeTestMethods()并随机播放方法列表。

要使用您创建的RunnerFactory,您必须在要使用随机执行顺序的每个类的@Parameterized.UseParametersRunnerFactory(Parallelized.RunnerFactory.class)正下方添加@RunWith(Parallelized.class)

注意:如果不添加此注释,则junit将使用默认运行器而非自定义运行器 - >没有变化。

public static class RunnerFactory implements ParametersRunnerFactory {
    @Override
    public org.junit.runner.Runner createRunnerForTestWithParameters(TestWithParameters test) throws InitializationError {
        return new CustomRunnerWithParameters(test);
    }

}

public static class CustomRunnerWithParameters extends BlockJUnit4ClassRunnerWithParameters {
    private final Object[] parameters;

    @Override
    protected List<FrameworkMethod> computeTestMethods() {
        List<FrameworkMethod> tests = new ArrayList<FrameworkMethod>(super.computeTestMethods());
        Collections.shuffle(tests);
        return tests;
    }

    public CustomRunnerWithParameters(TestWithParameters test) throws InitializationError {
        super(test);
        parameters = test.getParameters().toArray(new Object[test.getParameters().size()]);
    }

    @Override
    public Object createTest() throws Exception {
        return getTestClass().getOnlyConstructor().newInstance(parameters);
    }
}

Aroidans评论后编辑:

我忘了补充说我在我的自定义运行器中使用覆盖的getChildren方法扩展了参数化以调整测试的执行顺序。但他的回答也是有效的。

    @Override
    protected List<Runner> getChildren() {
        ArrayList<Runner> runner = new ArrayList<>(super.getChildren());
        if (NUM_THREADS > 1) {
            Collections.shuffle(runner);
        }
        return runner;
    }

答案 1 :(得分:1)

我发现随机化参数化测试顺序的最简单方法是使用参数对集合进行随机播放。

以Fibonacci样本测试为例。

@Parameters(name= "{index}: fib[{0}]={1}")
public static Iterable<Object[]> data() {
    Iterable<Object[]> tests = Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },{ 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
    Collections.shuffle((List<?>) tests);
    return tests;
}

这会随机化运行使用相同方法的测试的顺序。使用computeTestMethod()不起作用,因为只有一个方法执行所有测试。