我目前正在编写一个与Bamboo构建服务器交互的小库。使用pytest进行测试。我遇到了以下问题。我想测试一个运行的while循环,直到满足一些状态。阅读pytest doc,我试图“模拟”/ monkeypatch状态,但它并没有真正起作用。我可能在这里做了一些基本的错误: 这是有问题的while循环:
# 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创建了一个正面和负面_is_a_build_running
的夹具,如下所示:
@pytest.fixture(scope='function')
def mock_is_a_build_running():
return False
然后使用ThreadPool(这里解释为how to get the return value from a thread in python?)使用此测试方法,因为我还需要包含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完成,但到目前为止我只使用了这里描述的首选方式:http://pytest.org/latest/monkeypatch.html。
答案 0 :(得分:4)
所以,经过一番深入研究,我找到了一个满足我现在的解决方案。我想分享它,以防其他人遇到同样的问题。实际上它非常简单,并且使用https://gist.github.com/daltonmatos/3280885的一些辅助类我想出了以下测试代码:
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)
也可以修改它以在某个时刻返回异常并再次检查。如果有人有更清洁的解决方案(我相信),我会将问题保持更长时间。
答案 1 :(得分:1)
我为这种函数添加了一个参数running_times_for_test
(默认为-1),如果running_times达到0,那么我打破了无限循环。如果running_time等于-1(默认值),则照常执行。
答案 2 :(得分:0)
如@Simin Jie
所述,您可以使用默认的反参数。
这是一个例子:
代码本身
def start(number_of_iterations=-1):
while number_of_iterations != 0:
# HERE IS THE MAIN LOGIC
number_of_iterations -= 1
return 'BLA BLA BLA'
测试
def test_start(self):
results = start(
number_of_iterations=1,
)
self.assertEqual(
first=results,
second='BLA BLA BLA',
)