我有一个非常简单的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看起来可能会成功。
问题摘要:
InputData()
中的逻辑,如果是,如何?waitForCondition()
经过测试,我是否应该忽略InputData()
的测试?waitForCondition()
? 答案 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/