如何使用线程执行unit testing?

执行摘要:当线程中抛出断言错误时,unit testing不会消失。 这是有道理的,因为不应该允许一个线程崩溃另一个线程。 问题是我如何1)在第一个辅助线程崩溃时使整个测试失败,或者2)循环并确定每个线程完成后的状态(参见下面的代码)。 执行后者的一种方法是通过具有每线程状态变量,例如“boolean [] status”并且具有“status [i] == false”意味着线程失败(这可以被扩展以捕获更多信息)。 但是,这不是我想要的:我希望它在抛出断言错误时就像任何其他unit testing一样失败。 这有可能吗? 这是可取的吗?

我感到无聊,我决定在我的unit testing中产生一堆线程,然后让它们调用一个服务方法,只是为了它。 代码看起来大致如下:

Thread[] threads = new Thread[MAX_THREADS]; for( int i = 0; i  " + ID; logger.debug( message, t ); throw new IllegalStateException( message, t ); // need to wrap throwable in a // run time exception so it will compile } } } ); } 

在此之后,我们将遍历线程数组并启动每个线程。 之后我们将等待他们全部完成。 最后,我们将对结果引用执行一些检查。

 for( Thread thread : threads ) thread.start(); logger.debug( "waiting for threads to finish ..." ); boolean done = false; while( !done ) { done = true; for( Thread thread : threads ) if( thread.isAlive() ) done = false; } for( int i = 0; i < resultRefs.length; i++ ) { assertTrue( "you've got the world messed, dawg!", myCondition(resultRefs[i]) ); 

这是问题所在。 你有没有注意到那个讨厌的try-catch-throwable块? 我刚刚补充说,作为一个临时黑客,所以我可以看到发生了什么。 在runTest(String)中,会产生一些断言,例如assertNotNull(null),但由于它位于不同的线程中,因此不会导致unit testing失败!

我的猜测是,我们需要以某种方式迭代线程数组,检查每个数据的状态,并在线程以令人讨厌的方式终止时手动导致断言错误。 提供此信息的方法的名称是什么(死线程的堆栈跟踪)。

并发性是unit testing非常困难的事情之一。 如果您只是想测试每个线程中的代码是否正在执行它应该测试的内容,那么您应该只测试此上下文的代码。 如果在此示例中,线程协作以达到结果,则可以在不使用线程的情况下测试该协作。 这将通过顺序执行所有协作部分来完成。 如果你想测试竞争条件和这些东西,unit testing不是最好的方法。 您将获得有时会失败但有时不会失败的测试。 总而言之,我认为可能是你的问题是你的unit testing水平太高了。 希望这可以帮助

谷歌测试博客有一篇关于这个主题的优秀文章非常值得一读: http : //googletesting.blogspot.com/2008/08/tott-sleeping-synchronization.html

它是用Python编写的,但我认为这些原则可以直接转移到Java。

在multithreading环境中进行unit testing很困难……因此需要进行一些调整。 unit testing必须是可重复的。确定性的。 因此,具有多个线程的任何内容都不符合此条件。 multithreading测试也往往很慢。

  • 我要么试着看看我是否可以在单个线程上进行测试..被测逻辑是否确实需要多个线程。
  • 如果这不起作用,请使用成员变量方法,在所有线程完成运行时,可以在测试结束时检查预期值。

嘿,好像还有另一个问题就像这样。 在tdd yahoogroup unit testingmultithreading应用程序时查看我的post,找到更长时间讨论的链接?

您的可运行包装器应该将exception对象传递回测试类,然后您可以将它们存储在集合中。 完成所有测试后,您可以测试该集合。 如果它不为空,则遍历每个exception和.printStackTrace()然后失败。

实现一个UncaughtExceptionHandler ,它设置一些标志(Threads peridocially检查)并在每个Thread上设置它 。

Junit并发线程测试的另一个流行选项是Matthieu Carbou使用自定义JunitRunner和简单注释的方法。

请参阅完整文档

通过使用特殊的同步对象,可以使unit testing失败。 请查看以下文章: Sprinkler – 高级同步对象

我将尝试解释这里的要点。 您希望能够将内部线程故障外部化到主线程,在您的情况下是测试。 因此,您必须使用内部线程和测试将用于彼此同步的共享对象/锁。 请参阅以下测试 – 它通过调用名为Sprinkler的共享对象创建一个模拟抛出exception的线程。 主线程(测试)在Sprinkler.getInstance()。await(CONTEXT,10000)上被阻塞,在调用时释放它 – 将是空闲的并捕获抛出的exception。 在catch块中,您可以编写未通过测试的断言。

  @Test public void testAwait_InnerThreadExternalizeException() { final int CONTEXT = 1; final String EXCEPTION_MESSAGE = "test inner thread exception message"; // release will occur sometime in the future - simulate exception in the releaser thread ExecutorServiceFactory.getCachedThreadPoolExecutor().submit(new Callable() { @Override public Void call() throws Exception { Sprinkler.getInstance().release(CONTEXT, new RuntimeException(EXCEPTION_MESSAGE)); return null; } }); Throwable thrown = null; try { Sprinkler.getInstance().await(CONTEXT, 10000); } catch (Throwable t) { // if the releaser thread delivers exception it will be externelized to this thread thrown = t; } Assert.assertTrue(thrown instanceof SprinklerException); Assert.assertEquals(EXCEPTION_MESSAGE, thrown.getCause().getMessage()); }