并发JUnittesting

我有一个很大的JUnittesting套件,我很想同时运行所有的testing,原因有两个:

  • 利用多个内核来更快地运行整个testing套件
  • 希望能够检测到由于非线程安全的全局对象造成的一些错误

我认识到这将迫使我重构一些代码,使其线程安全,但我认为这是一件好事:-)

让JUnit同时运行所有testing的最好方法是什么?

你是否修复了JUnit? TestNG提供了很好的multithreadingtesting,它与JUnittesting兼容(你需要做一些改变)。 例如,你可以运行一个像这样的testing:

@Test(threadPoolSize = 3, invocationCount = 9, timeOut = 10000) public void doSomething() { ... } 

这意味着doSomething()方法将被3个不同的线程调用9次。

我强烈推荐TestNG

我正在寻找这个问题的答案,并根据这里的答案和我在别处读到的内容,看起来好像现在还没有一种简单的开箱即用的方式来并行地运行现有的testingJUnit的。 或者如果有的话,我没有find它。 所以我写了一个简单的JUnit Runner来完成这个任务。 请随意使用它; 请参阅http://falutin.net/2012/12/30/multithreaded-testing-with-junit/了解MultiThreadedRunner类的完整说明和源代码。; 通过这个类,你可以像下面这样注释你现有的testing类:

 @RunWith(MultiThreadedRunner.class) 

下面的代码应该能够达到你的要求,这个要求是从德国的JUnit Profiwissen书籍中得到的 ,它包含了一些提示,可以并行地testing东西,也可以通过使用多核而不是单核来减less执行时间。

JUnit 4.6引入了一个ParallelComputer类,它提供了testing的并行执行。 但是,直到JUnit 4.7提供了为父级运行者设置自定义调度程序的可能性之后,才能公开访问此function。

 public class ParallelScheduler implements RunnerScheduler { private ExecutorService threadPool = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors()); @Override public void schedule(Runnable childStatement) { threadPool.submit(childStatement); } @Override public void finished() { try { threadPool.shutdown(); threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Got interrupted", e); } } } public class ParallelRunner extends BlockJUnit4ClassRunner { public ParallelRunner(Class<?> klass) throws InitializationError { super(klass); setScheduler(new ParallelScheduler()); } } 

如果你现在使用@RunWith(ParallelRunner.class)注解一个testing类,每个方法将在它自己的线程中运行。 而且,在执行的机器上将会有尽可能多的活动线程(仅限于CPU核心)。

如果多个类应该并行执行,你可以定义一个这样的定制的套件:

 public class ParallelSuite extends Suite { public ParallelSuite(Class<?> klass, RunnerBuilder builder) throws InitializationError { super(klass, builder); setScheduler(new ParallelScheduler()); } } 

然后使用@RunWith(ParallelSuite.class)更改@RunWith(Suite.class) @RunWith(ParallelSuite.class)

您甚至可以利用WildcardPatternSuite的function,通过直接从该套件进行扩展,而不是像之前的示例那样对Suite进行扩展。 这使得您可以进一步通过任何@Category来过滤unit testingfe – 一个只执行UnitTest注释类别的TestSuite可以如下所示:

 public interface UnitTest { } @RunWith(ParallelSuite.class) @SuiteClasses("**/*Test.class") @IncludeCategories(UnitTest.class) public class UnitTestSuite { } 

一个简单的testing用例现在可以像这样:

 @Category(UnitTest.class) @RunWith(MockitoJUnitRunner.class) public class SomeClassTest { @Test public void testSomething() { ... } } 

UnitTestSuite将执行在以子目录结尾的子目录中find的每个类,并且具有并行指定的@Category(UnitTest.class) – 取决于可用的CPU内核数量。

我不知道是否可以变得比这更简单:)

显然Mathieu Carbou已经完成了并发的实施,可以帮助!

http://java.dzone.com/articles/concurrent-junit-tests

OneJunit

 @RunWith(ConcurrentJunitRunner.class) @Concurrent(threads = 6) public final class ATest { @Test public void test0() throws Throwable { printAndWait(); } @Test public void test1() throws Throwable { printAndWait(); } @Test public void test2() throws Throwable { printAndWait(); } @Test public void test3() throws Throwable { printAndWait(); } @Test public void test4() throws Throwable { printAndWait(); } @Test public void test5() throws Throwable { printAndWait(); } @Test public void test6() throws Throwable { printAndWait(); } @Test public void test7() throws Throwable { printAndWait(); } @Test public void test8() throws Throwable { printAndWait(); } @Test public void test9() throws Throwable { printAndWait(); } void printAndWait() throws Throwable { int w = new Random().nextInt(1000); System.out.println(String.format("[%s] %s %s %s",Thread.currentThread().getName(), getClass().getName(), new Throwable ().getStackTrace()[1].getMethodName(), w)); Thread.sleep(w); } } 

多个JUnits:

 @RunWith(ConcurrentSuite.class) @Suite.SuiteClasses({ATest.class, ATest2.class, ATest3.class}) public class MySuite { } 

你也可以试试HavaRunner 。 这是一个默认运行testing的JUnit运行器。

HavaRunner也有方便的套件:你可以通过在类上添加注解@PartOf(YourIntegrationTestSuite.class)来声明一个testing是一个套件的成员。 这种方法不同于JUnit,你在suite类中声明了suite成员。

另外,HavaRunner套件还可以传入重量级的对象,比如embedded的Web应用程序容器。 然后HavaRunner将这个重量级的对象传递给每个套件成员的构造函数。 这消除了对@BeforeClass@AfterClass注释的需求,这是有问题的,因为它们促进了全局可变状态,这又使得并行化变得困难。

最后,HavaRunner具有场景 – 一种针对不同数据运行相同testing的方法。 scheme减less了复制testing代码的需要。

HavaRunner已经在两个中等规模的Java项目中进行了testing。

PS。 我是HavaRunner的作者,我会很感激你的反馈意见。