Python 如何使用pytest测试无限while循环
我目前正在编写一个与竹子构建服务器交互的小库。测试是使用pytest完成的。我被以下问题困住了。我想测试一个while循环,它运行到满足某种状态为止。在阅读pytest文档时,我试图“mock”/monkeypatch状态,但它并没有真正起作用。我可能在这里犯了一些基本错误: 这是有问题的while循环:Python 如何使用pytest测试无限while循环,python,unit-testing,mocking,pytest,monkeypatching,Python,Unit Testing,Mocking,Pytest,Monkeypatching,我目前正在编写一个与竹子构建服务器交互的小库。测试是使用pytest完成的。我被以下问题困住了。我想测试一个while循环,它运行到满足某种状态为止。在阅读pytest文档时,我试图“mock”/monkeypatch状态,但它并没有真正起作用。我可能在这里犯了一些基本错误: 这是有问题的while循环: # determine current status running = self._is_a_build_running() # turn on and off r
# determine current status
running = self._is_a_build_running()
# turn on and off running powerplug while building
while running:
self.feedback.turn_off_success()
self.feedback.turn_on_running()
time.sleep(self.blinker_time)
self.feedback.turn_off_running()
self._update_builds_status()
running = self._is_a_build_running()
因此,我在pytest中尝试的是为一个正的和一个负的\u创建一个fixture,该fixture运行如下所示:
@pytest.fixture(scope='function')
def mock_is_a_build_running():
return False
然后使用ThreadPool(此处解释)使用此测试方法,因为我还需要包含while循环的方法的结果
def test_update_status_running(bamboopickups, monkeypatch,
mock_update_overall_data_positive,
mock_update_builds_status_positive,
mock_is_a_build_running):
monkeypatch.setattr('BambooPickup._update_overall_data', lambda x: mock_update_overall_data_positive)
monkeypatch.setattr('BambooPickup._update_builds_status', lambda x: mock_update_builds_status_positive)
pool = ThreadPool(processes=1)
async_result = pool.apply_async(bamboopickups.update_status())
monkeypatch.setattr('BambooPickup._update_overall_data', lambda x: mock_update_overall_data_positive)
monkeypatch.setattr('BambooPickup._is_a_build_running', lambda x: mock_is_a_build_running)
actual = async_result.get()
expected = True
assert actual == expected
使用pytest mock可能很容易做到这一点,但到目前为止,我只使用了这里描述的首选方法:。因此,在深入研究这一问题之后,我找到了一个目前让我满意的解决方案。我想分享一下,以防其他人也遇到同样的问题。实际上,它非常简单,通过使用来自的某个助手类,我产生了以下测试代码:
def test_update_status_running(bamboopickup, monkeypatch,
mock_update_overall_data_positive,
mock_update_builds_status_positive):
monkeypatch.setattr('pickups.bamboo.bamboopickup.BambooPickup._update_overall_data', lambda x: mock_update_overall_data_positive)
monkeypatch.setattr('pickups.bamboo.bamboopickup.BambooPickup._update_builds_status', lambda x: mock_update_builds_status_positive)
with mock.patch.object(bamboopickup, '_is_a_build_running') as mockfoo:
mockfoo.return_value = AlmostAlwaysTrue(2)
bamboopickup.update_status()
和助手类:
class AlmostAlwaysTrue(object):
def __init__(self, total_iterations=1):
self.total_iterations = total_iterations
self.current_iteration = 0
def __nonzero__(self):
if self.current_iteration < self.total_iterations:
self.current_iteration += 1
return bool(1)
return bool(0)
# Python >= 3
def __bool__(self):
if self.current_iteration < self.total_iterations:
self.current_iteration += 1
return bool(1)
return bool(0)
类AlmostAlwaysTrue(对象):
定义初始(自身,总迭代次数=1):
self.total\u迭代次数=total\u迭代次数
self.current_迭代=0
定义非零(自):
如果self.current\u迭代=3
定义(自我):
如果self.current\u迭代
还可以修改它,在某个时刻返回异常并再次检查该异常。我把这个问题保留得更久一些,以防有人有更干净的解决方案(我相信) 我为这类函数添加了一个参数
running_times_for_test
(默认值为-1),如果running_times达到0,那么我就打破了无限循环。如果running_time等于-1(默认值),照常执行。正如前面提到的@Simin Jie
一样,可以使用默认的计数器参数。
举个例子:
代码本身
def start(迭代次数=-1):
而迭代次数!=0:
#这是主要的逻辑
迭代次数-=1
返回“blablabla”
测试
def测试_启动(自):
结果=开始(
迭代次数=1,
)
自我评价资格(
第一个=结果,
第二,='blablabla',
)
听起来是解决这一问题的另一种有效方法:)