让我们假设我有下面的方法需要测试:
@Autowired
private RoutingService routingservice;
public void methodToBeTested() {
Object objectToRoute = initializeObjectToRoute();
if (someConditions) {
routingService.routeInOneWay(objectToRoute);
} else {
routingService.routeInAnotherWay(objectToRoute);
}
}
在这种情况下,RoutingService
在单独的线程中运行,因此在它的构造函数中我们有以下内容:
Thread thread = new Thread(this);
thread.setDaemon(true);
thread.start();
问题是RoutingService
改变了objectToRoute
的状态,这正是我想要检查的,但这不会立即发生,因此测试失败。然而,如果我添加Thread.sleep()
,那么它就可以工作了,但据我所知,这是一个不好的做法。
在这种情况下,如何避免Thread.sleep()
?
7条答案
按热度按时间efzxgjgh1#
如果你正在测试
methodToBeTested
方法的[Unit Test],你应该简单地模拟routingservice
。您不应该测试
methodToBeTested
调用的任何方法。然而,听起来你想测试
RoutingService
(你说“问题是RoutingService
改变了objectToRoute
的状态,这正是我想检查的”)。要测试
RoutingService
方法,应该为这些方法编写单独的单元测试。hzbexzde2#
我建议使用awaitility来同步异步测试。例如,假设您有一个在某些线程操作后得到设置的结果对象,并且您想要测试它。你写这样的声明:
它等待最多100秒,或,直到满足Assert。例如,如果getResult()在0-100秒之间返回非空值,则执行将继续,而不像Thread.sleep那样,无论结果是否存在,都会在给定时间内保持执行。
qojgxg4l3#
您可以模拟
objectToRoute
来设置CompletableFuture
的值,然后在Assert中调用get
。这将等待直到值被设置后才继续。然后设置一个超时@Test(timeout=5000)
,以防从未设置该值。这样做的好处是,测试不会等待超过必要的时间,并且由于时间太短而失败的可能性更小,因为您可以使超时时间比正常情况大得多。
66bbxpm54#
这要看情况。正如本绿色在他的评论中所说,睡眠在测试中是危险的,因为它可以隐藏一个竞争条件。您知道整体设计是否包含这样的竞态条件,即服务可能在路由准备好之前被使用。如果是这样,你应该在代码中修复它,例如通过测试一个 ready 条件,并在你的测试类中测试它。
如果你知道它不会发生,你应该在你的主代码和测试类中记录它。这将是一个完美的理由睡觉。
(我假设这是一个集成测试-对于单元测试 * 模拟 * 应该足够了,因为你在其他答案中说过)
x759pob25#
使用Object.wait()
我们已经使用了一些从目录或.ZIP存档中获取文件的异步进程。我们在其他地方使用文件的内容,而异步文件继续阅读。
我们测试它们的方法是在通信对象上执行
wait()
--在我们的例子中,它是一个队列--所以每当有一个新文件准备使用并保持工作时,异步进程都将执行queue.notifyAll()
。在另一端,消费者将一次处理一个项目,直到队列为空,然后queue.wait()
等待更多。我们使用一个特殊的对象通过队列来表示没有更多的项目要处理。在你的例子中,我假设你想要检查的对象,
objectToRoute,
并没有真正在你想要测试的方法中创建。你可以在测试中使用wait()
,在你想要测试的方法中使用notifyAll()
,methodToBeTested.
我知道这会在你的生产代码库中引入额外的代码行,但是没有人在等待它,它应该是无害的。它会以这样的方式结束:在你的测试类中,会有这样的东西:
我知道在这个简单的例子中没有太大的意义,因为示例系统不是多线程的。我假设在
routeInOneWay
和routeInAnotherWay
方法中添加了多线程扭曲;因此,这些都是调用notifyAll()
方法。这里有一些代码片段,作为示例代码来指明我们解决方案的方向。
在异步工作者端或生产者端:
在消费者方面:
ohtdti5x6#
从java 9开始,你可以使用
CompleteableFuture
的delayedExecutor
方法来避免Thread.sleep
和它的SonarLint警告。这是基本模式,根据您的需求进行调整:
s5a0g9ez7#
你可以在Junit测试用例中将value作为零传递,而不是避免Thread.sleep()。