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

Java 单元测试非阻塞方法(异步测试),java,multithreading,unit-testing,Java,Multithreading,Unit Testing,我有一个非常简单的Check类,它有一个blockingwaitForCondition()方法。这种方法是阻塞的。我想为这个方法创建一些单元测试。首先,该方法应该在满足条件时返回。第二,方法在被中断时应该返回 在内部,Check类有一个ArrayBlockingQueue并调用它的take()方法,因此我的测试实际上是正确地编码了条件的逻辑(应该是这样的)。 在应用程序中,Check类的数据由另一个线程通过InputData方法提供。InputData方法对传入数据执行逻辑,并在满足条件时在A

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

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

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

但是,如果
InputData
功能正常,那么检查
waitForCondition()
方法本身就有问题。它实际上只是简单的代码:

try {
        myArrayBlockingQueue.take();
        return true;
    } catch (InterruptedException ex) {
        return false;
    }
所以我想知道这是否值得想象中的麻烦:一个测试用
检查创建另一个线程,调用它的
waitForCondition()
,然后在完成时返回一些东西。也许,使用Executor服务。模糊部分是如何同步
assertTrue(…)
。我发现了这个,看起来它可能会起作用

问题摘要:

  • 我是否应该更改设计以测试
    InputData()
    中的逻辑?如果是,如何更改
  • 只要测试了
    InputData()
    ,我是否应该省略
    waitForCondition()
    的测试
  • 还是只做需要做的事情(有点复杂的单元测试)并直接测试
    waitForCondition()
    更好
    谢谢你的链接!我也遇到了一些类似的问题,也许这种联系比我做的更好。(我还想看看这个问题的其他答案——这是个好问题)

    如果您不介意更改(至少暂时更改)您的实际代码(是的,这不是通常的单元测试实践!),您可以执行我调用的操作

    在我的实现中,您创建了一个类,该类读取属性(或映射)以在特定的唯一点“做一些有趣的事情”。e、 你的财产可能会说

    myClass.myMethod.blockingQueueTake = interrupt:
    myClass.myLongCalculation = throw: java.lang.ArithmeticException(Failed to converge)
    
    在代码中,添加测试行,例如,就在
    队列的前面。take()
    ,添加

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

    优点是,所有事情都是在真实的代码中发生的,而不是在一些模拟代码中发生的,这些代码可能会变得非常复杂。(在我的例子中,软件比较旧,不是为单元测试而编写/设计的,因此进行模拟非常困难)缺点是您可能希望在以后删除或注释掉代码。所以它实际上不是一个持续集成类型的单元测试,它更像是一个一次性的真正严肃的实际调试。所以,我承认,这离理想还很远,但是,它确实为我找到了一堆bug

    > p>如果在检查类的构造函数中注入ARARYBACKIGKEN队列实例,那么您的测试可以在测试中间注入适当的值。

    然后,您可以在超时的情况下运行单元测试,如果它在100ms左右的时间内没有返回,则会失败。

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


    +1个有趣的想法。在某些测试条件下,可以模拟注入的队列抛出InterruptedException,等待很长时间,等等……好主意。出于测试目的,我向
    Check
    类添加了一个构造函数,它按照您的建议注入队列。然后,我可以通过直接设置和读取实际队列(而不是模拟)来测试所有公共方法。我只需要使用一个模拟来测试InterruptedException。使用Mockito:
    when(queueMock.take()).thenthow(newinterruptedexception())因此,在这种情况下,我们可以在没有任何异步/计时问题的情况下进行测试。如果阻塞对象的数量很小,并且您的代码是结构化的,因此可以注入它们,那么这是一个很好的解决方案。