用于在Java中断言多线程代码的库

Fab*_*eto 7 java multithreading unit-testing

作为TDD从业者,我想测试我编码的所有内容.

在过去的几年里,我一直在编写许多多线程代码,而且我的测试中有一部分一直困扰着我.

当我必须断言在run()循环期间可能发生的事情时,我最终得到了一些像这样的断言:

assertEventually(timeout, assertion)
Run Code Online (Sandbox Code Playgroud)

我知道Mockito有一个解决方案,但仅限于验证电话.我也知道JUnit有一个超时属性,可以避免挂起(或永久)测试.但我想要的是能够让我断言可能随着时间变成真实的东西.

所以我的问题是,有没有人知道提供此功能的库?

这是我到目前为止的解决方案:

private void assertEventually(int timeoutInMilliseconds, Runnable assertion){
    long begin = System.currentTimeMillis();
    long now = begin;
    Throwable lastException = null;
    do{
        try{
            assertion.run();
            return;
        }catch(RuntimeException e){
            lastException = e;
        }catch(AssertionError e){
            lastException = e;
        }
        now = System.currentTimeMillis(); 
    }while((now - begin) < timeoutInMilliseconds);
    throw new RuntimeException(lastException);
}
Run Code Online (Sandbox Code Playgroud)

使用它最终会像这样:

assertEvetuallyTrue(1000, new Runnable() {
        public void run() {
            assertThat(Thread.activeCount()).isEqualTo(before);
        }
    });
Run Code Online (Sandbox Code Playgroud)

Jon*_*han 5

您可能想要查看的两个库:

  • ConcurrentUnit - 允许您从任何线程执行断言,等待固定的时间
  • Awaitility - 允许您等待固定的时间或直到满足某些条件


rob*_*cox 1

从你使用的语言来看——断言某些事情可能是真的——听起来你正在走一条导致脆弱测试的道路。测试应该有二元结果——要么通过,要么失败,并且不存在灰色地带。

看看这个具体的例子,考虑到多线程的使用,我会建议这样的事情:

  • 重构您的设计,以便代码中的所有实际逻辑都可以作为同步执行的代码独立于多线程环境轻松运行,这将使围绕此编写单元测试变得相当简单。
  • 在所有这些代码之外实现线程管理 - 这将更难使用单元测试进行测试,因此您应该将其与代码的其余部分完全隔离,这样不会使其他代码更难以测试。
  • 开始构建一个高级系统测试套件,该套件将系统(或其大型组件)作为一个整体执行,通过应用程序的外部边界驱动您的测试。这些将涵盖线程处理代码,以及测试系统中各种组件的集成。此外,您不必编写处理线程的特定测试逻辑 - 当您测试它时,它们应该只在系统内部运行。

以这种方式拆分测试的另一个优点是,您可以为单元测试和系统测试创建单独的测试套件,这应该有助于保持单元测试套件的快速和精简(以便您可以在开发过程中更轻松、更频繁地运行它)。任何涉及超时的测试(即本例中的系统测试)将需要更长的时间来执行,因此更适合仅偶尔运行 - 这种方法使这更容易做到。