我在python(2.7)中有一个foo方法,如果foo没有工作,我会在5分钟后放弃。
def keep_trying(self):
timeout = 300 #empirically derived, appropriate timeout
end_time = time.time() + timeout
while (time.time() < end_time):
result = self.foo()
if (result == 'success'):
break
time.sleep(2)
else:
raise MyException('useful msg here')
我知道来自foo()的一些可能的结果,所以我使用mock伪造那些返回值。问题是,我不希望测试在看到异常之前运行5分钟。
有没有办法覆盖超时的本地值?我想这只是几秒钟,所以我可以看到循环尝试几次,然后放弃并加注。
以下不起作用:
@patch.object(myClass.keep_trying, 'timeout')
@patch.object(myClass, 'foo')
def test_keep_trying(self, mock_foo, mock_timeout):
mock_foo.return_value = 'failed'
mock_timeout.return_value = 10 # raises AttributeError
mock_timeout = 10 # raises AttributeError
...
答案 0 :(得分:15)
不是试图模拟timeout
的值,而是要模拟time.time()
的返回值。
e.g。
@patch.object(time, 'time')
def test_keep_trying(self, mock_time):
mock_time.side_effect = iter([100, 200, 300, 400, 500, 600, 700, 800])
...
现在第一次调用time.time()
时,你会得到100的值,所以它会在你的while循环几圈之后超时。您还可以模拟time.sleep
并计算调用它的次数,以确保部分代码正常工作。
另一种方法(与上面的方法不完全正交)是允许用户将可选的timeout关键字传递给函数:
def keep_trying(self, timeout=300):
...
这允许您在测试中指定您想要的任何超时(以及将来不想等待5分钟的代码; - )。
答案 1 :(得分:14)
您无法模拟函数的局部变量。为了使代码更容易测试,请将其更改为,例如:
def keep_trying(self, timeout=300):
end_time = time.time() + timeout
# etc, as above
因此,测试以较短的超时运行它会变得微不足道!