技术开发 频道

扩展 JUnit 测试并行程序

  【IT168 技术文章】随着多核的普及,并行程序的开发已经提上日程。相对串行程序而言,并行程序更有可能出错。一方面,并行程序的执行序列具有很强的随机性,线程交错执行的序列可能每次都不一样,而只要一个序列有问题,整个程序就是不正确的。另一方面,并行程序对大多数程序员来说,都是一个新的领域,经验相对较少,这是容易出错的另外一个因素。

  既然如此,我们就更需要仔细的测试我们的并行程序和组件了。目前已经有一些 JUnit 扩展可以创建多个线程,同时运行多个测试用例,从而加快测试用例集的执行速度,如 p-unit 。但对于测试并行程序和组件,这些功能并不能满足所有的需求。因为开发人员通常希望可以精确地控制多个线程之间的同步。

  与测试顺序程序相同,我们希望能在测试并行操作之前,首先准备一些测试数据。然后,启动多个线程测试执行不同的操作。最后,等待所有线程结束之后,检验结果的正确性。在第二阶段中,多个线程能以任意的次序交错执行。结果的正确性检查应与线程的执行测序无关。

  标准 JUnit 只捕捉来自主线程的 Exception 。而其他线程中产生的 Exception 则会安静地被忽略掉,使得我们在子线程运行出错的情况下仍旧能得到“ Green Bar ”。这显然不是程序员喜欢的测试行为,我们希望测试结果能正确地反映所有线程的运行结果。

  这种用于并行程序的测试模式会在测试并行程序时会不断的重复。如果开发人员每次都需要重复创建这些框架,不仅繁琐,而且容易引入错误。通过使用以下介绍的简单扩展,可以使并行程序的测试变得和顺序程序一样简单。这种扩展并不影响 JUnit 的其他特性以及各种 IDE 的 JUnit 插件的使用。

  下载并使用扩展框架

  首先,我们给出一个使用新扩展进行并行测试的例子。

  例 1. 使用 JUnit 扩展进行并行测试

1 /**
2 * @author Zhi Gan
3 *
4 */
5 @RunWith(Parallelized.class)
6 @ParallelSetting(threadNumber = { 1, 2, 4, 8 })
7 public class TestThreaded {
8      Set<String> strSet;
9
10      @Before
11      public void setUp() {
12          strSet = new LockFreeSet();
13      }
14
15      @Test
16      public void doNothing() {
17
18      }
19     
20     @InitFor("testThread")
21      public void putSomeData(int size){
22          strSet.add("putSomeData");
23      }
24
25     @Threadedpublic void testThread(int rank, int size) {
26          // every thread adds element to set
27          strSet.add("abcde" + rank);
28      }
29
30     @CheckFor("testThread")
31      public void checkResult(int size) {
32          assertEquals(size+1, strSet.size());
33      }
34
35      public static void main(String[] args) {
36          for (int i = 0; i < 10; i++)
37              JUnitCore.runClasses(TestThreaded.class);
38      }
39 }

 

  如果我们在 Eclipse 中运行测试,那么测试完毕之后的 JUnit 视图如下所示:

  图 1. 并行测试的完成结果

  接下来,我们模拟子线程在运行时抛出异常。

  例 2. 子线程运行时异常

1 /**
2 * @author Zhi Gan
3 *
4 */
5 @RunWith(Parallelized.class)
6 @ParallelSetting(threadNumber = { 1, 2, 4, 8 })
7 public class TestThreaded {
8      Set<String> strSet;
9
10      @Before
11      public void setUp() {
12          strSet = new LockFreeSet();
13      }
14
15      @Test
16      public void doNothing() {
17
18      }
19     
20     @InitFor("testThread")
21      public void putSomeData(int size){
22          strSet.add("putSomeData");
23      }
24
25     @Threadedpublic void testThread(int rank, int size) {
26          // throw a runtime error in spawned thread
27          throw new RuntimeError();
28      }
29
30     @CheckFor("testThread")
31      public void checkResult(int size) {
32          assertEquals(size+1, strSet.size());
33      }
34
35      public static void main(String[] args) {
36          for (int i = 0; i < 10; i++)
37              JUnitCore.runClasses(TestThreaded.class);
38      }
39 }

 

  如果我们在 Eclipse 中运行测试,那么测试完毕之后的 JUnit 视图如下所示:

  图 2. 并行测试的完成结果

  从上图可以看出,我们的并行测试用例通过了测试,并且它们在使用不同线程运行时都能正常的工作。而串行的测试方法 (doNothing) 的执行结果则完全和之前一样工作正常。也就是说,串行和并行测试可以在一个测试类中同时出现。

0
相关文章