单元测试非阻塞方法(异步测试)

时间:2012-07-11 14:47:42

标签: java multithreading unit-testing

我有一个非常简单的Check类,它有一个阻塞waitForCondition()方法。这种方法是封锁的。我想为这个方法创建一些单元测试。首先,该方法应在满足条件时返回。其次,该方法应在中断时返回。

Check类在内部有一个ArrayBlockingQueue并调用其take()方法,所以我的测试实际上是关于正确编码条件的逻辑(应该是这样)。 在应用程序中,Check类的数据由另一个线程通过InputData方法提供。 InputData方法对传入数据执行逻辑,并在满足条件时将虚拟对象放入ArrayBlockingQueue中。这会导致waitForCondition()返回。

所以我的第一个想法是我可以通过模拟测试InputData并检查在满足条件时将虚拟对象添加到队列中。这将需要更改类的设计,因为队列是私有数据成员(除非可以模拟私有数据)。当条件满足时,不是InputData直接添加到队列,而是必须调用可以被模拟的东西。

但是,鉴于waitForCondition()正常运行,存在检查InputData方法本身的问题。这真的很简单:

try {
        myArrayBlockingQueue.take();
        return true;
    } catch (InterruptedException ex) {
        return false;
    }

所以我想知道它是否值得想象的麻烦:一个用Check创建另一个线程的测试,调用它的waitForCondition(),然后在完成时返回一些东西。也许,使用Executor服务。模糊部分是如何同步assertTrue(...)。我发现这个article on asynchronous testing看起来可能会成功。

问题摘要:

  1. 我应该更改设计以测试InputData()中的逻辑,如果是,如何?
  2. 只要waitForCondition()经过测试,我是否应该忽略InputData()的测试?
  3. 或者更好地完成需要完成的工作(有点复杂的单元测试)并直接测试waitForCondition()

3 个答案:

答案 0 :(得分:3)

如果在Check类的构造函数中注入ArrayBlockingQueue实例,那么测试可以在测试过程中注入适当的值。

然后你可以用超时运行单元测试,如果它在100ms左右没有返回就失败。

答案 1 :(得分:1)

感谢您的好链接!我遇到了一些类似的问题,也许这个链接比我做的更好。 (我也有兴趣看到这个问题出现了什么其他答案 - 这是一个很好的问题)

如果您不介意更改(至少暂时)您的实际代码(是的,这不是通常的单元测试练习!)您可以执行我称之为"Error Injection"的操作

在我的实现中,您创建了一个类,该类从属性(或Map)读取到在特定的唯一点“做一些有趣的事情”。例如你的房产可能会说

myClass.myMethod.blockingQueueTake = interrupt:
myClass.myLongCalculation = throw: java.lang.ArithmeticException(Failed to converge)

在您的代码中,您添加测试行,例如在queue.take()之前,添加

TestSimulator.doCommand("myClass.myMethod.blockingQueueTake");

优点是一切都在真实的代码中发生,而不是一些Mock,它可能变得非常毛茸茸。 (在我的情况下,SW是较老的,没有编写/设计用于单元测试,因此制作模拟非常困难)缺点是您可能希望之后删除或注释掉代码。所以它真的不是一个连续集成型单元测试,它更像是一次性非常严重的现实调试。所以,我承认,它远非理想,但它确实为我找到了一堆错误!

答案 2 :(得分:0)

您还可以使用“test runner”类在循环中运行断言。循环将在try / catch中运行断言。异常处理程序只会尝试再次运行断言,直到超时到期。我最近写了一篇关于这种技术的博客文章。这个例子是用groovy编写的,但这个概念应该很容易适用于Java。

http://www.greenmoonsoftware.com/2013/08/asynchronous-functional-testing/