pytest如何模拟线程.Timer

时间:2019-01-12 10:18:57

标签: python unit-testing pytest

我了解如何尝试模拟当前时间。问题是我的程序使用了threading.Timer,它似乎不受模拟时间的影响。

当然这个问题以前发生过。我该如何“睡觉”我的单元测试或以某种方式嘲笑时间的流逝?

调用sleep可能不是一个好主意,因为实际的执行速度取决于单元测试所运行的硬件。

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

如果您查看the source for threading.Timer,则可以看到延迟效果来自Timer(本身就是Thread),而只是在{{ 1}}对象。

您可以使用.wait()threading.Event来将unittest.mock实现替换为实际上不需要等待任何东西的实现。

答案 1 :(得分:0)

更新:您的评论最终阐明了您打算实现的目标,即不必等待测试中真实的60岁。已经有关于如何对与计时器一起使用的代码进行单元测试的主题的讨论:

基本思想是,使用一种称为“控制反转”的技术:代替允许被测系统(SUT)控制时间,请更改设计以使测试可以执行此操作。有许多不同的方法,例如a)将计时器对象转换为参数,或b)以可被测试覆盖的辅助方法在SUT中访问它,或者让SUT从工厂获得它(在测试过程中替换掉),或者使测试可以使用setter方法等将其覆盖。

原始答案(侧重于其他方面):

从您的问题和评论中,我得出结论,对于您的测试,您接受测试的执行实际上将花费大约60s(引用您:“我需要测试该任务确实在60秒后执行了。”和“如何我可以“睡觉”我的单元测试[...]”。您想测试程序是否使用计时器执行任务-这是一个集成测试方案而不是单元测试方案。

测试描述仍然不是很准确,因此我会做一些假设。假设您要测试“任务”是否在例如59s之前执行,但也没有在例如61s之前执行。有几种方法可以实现此目的。一种简单的方法是,实际使用58s的睡眠,检查是否尚未执行任务(测试用例1),并让另一个测试用例的睡眠为61s,并检查任务是否已执行。但是,由于各种影响,它并不完全健壮,正如您已经提到的那样。您可以通过延长时间间隔来使其更健壮。

另一种方法需要进行设计更改:在程序中,您将在启动计时器之前立即读取时钟时间,并将此时间戳传递给计划的任务。在计划的任务中,第一件事是再次读取时钟。然后可以将此时间与其他时间戳进行比较。这些结果可用于测试,以读取时间戳或增量。这可能更准确,但仍然受操作系统引起的调度影响的影响。

我会说,由于这个问题是关于python程序的,因此您将不得不承受一定程度的不准确性。即使在具有使用C甚至汇编语言编写的程序的实时系统中,要达到很高的精度也是具有挑战性的-但是我们在这里谈论的是不同级别的精度(微秒或更好)。