Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使用pytest测试无限while循环_Python_Unit Testing_Mocking_Pytest_Monkeypatching - Fatal编程技术网

Python 如何使用pytest测试无限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

我目前正在编写一个与竹子构建服务器交互的小库。测试是使用pytest完成的。我被以下问题困住了。我想测试一个while循环,它运行到满足某种状态为止。在阅读pytest文档时,我试图“mock”/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中尝试的是为一个正的和一个负的
\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',
)

听起来是解决这一问题的另一种有效方法:)