并行化+参数化线程,每个线程的执行顺序随机
Parallelized + Parameterized threads with random execution order for each thread
我有一个 class 可以与参数并行运行我的测试。但是为了检查并发问题,我想以随机顺序执行测试。
例如。第一个线程上的 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());
}
}
好的,我找到了一个相当简单的解决方案:
您只需要一个 ParametersRunnerFactory,它可以创建 BlockJUnit4ClassRunnerWithParameters
类型的 Runner。
要随机化每个跑步者的测试顺序,您只需覆盖 computeTestMethods()
并打乱方法列表。
要使用您创建的 RunnerFactory,您必须在要使用随机执行顺序的每个 class 中的 @RunWith(Parallelized.class)
正下方添加 @Parameterized.UseParametersRunnerFactory(Parallelized.RunnerFactory.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;
}
我发现随机化参数化测试顺序的最简单方法是使用参数对集合进行洗牌。
以斐波那契样本测试为例。
@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() 不起作用,因为只有一种方法执行所有测试。
我有一个 class 可以与参数并行运行我的测试。但是为了检查并发问题,我想以随机顺序执行测试。 例如。第一个线程上的 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());
}
}
好的,我找到了一个相当简单的解决方案:
您只需要一个 ParametersRunnerFactory,它可以创建 BlockJUnit4ClassRunnerWithParameters
类型的 Runner。
要随机化每个跑步者的测试顺序,您只需覆盖 computeTestMethods()
并打乱方法列表。
要使用您创建的 RunnerFactory,您必须在要使用随机执行顺序的每个 class 中的 @RunWith(Parallelized.class)
正下方添加 @Parameterized.UseParametersRunnerFactory(Parallelized.RunnerFactory.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;
}
我发现随机化参数化测试顺序的最简单方法是使用参数对集合进行洗牌。
以斐波那契样本测试为例。
@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() 不起作用,因为只有一种方法执行所有测试。