首页 > 解决方案 > Python - 调用 psutil.process_iter 的模拟方法中的错误

问题描述

我有一个方法(如下),在一个用于查找和生成进程信息的模块utils.pypsutil.process_iter。dicts ( psutil.Process.as_dict) 基于给定进程的名称。如果进程名称不存在,或者遇到进程错误,则不会生成任何内容。该模块当然包含psutil.

def get_processes_by_name(process_name):
    for proc in psutil.process_iter():
        try:
            pinfo = proc.as_dict()

            if process_name == pinfo['name']:
                yield pinfo
        except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
            pass

我正在尝试为此方法编写许多单元测试,用于不同的场景,使用unittest.mock. 测试用例位于测试模块test_utils.py中。下面是一个例子。

    def test__process_instances_by_name__one_running_proc_matches_given_proc_name__one_proc_instance_generated(self):
        mock_proc1 = MagicMock()
        mock_proc1.as_dict = MagicMock(return_value={'name': 'some_other_proc_name'})

        mock_proc2 = MagicMock()
        mock_proc2.as_dict = MagicMock(side_effect=psutil.AccessDenied(2))

        mock_proc3 = MagicMock()
        mock_proc3.as_dict = MagicMock(return_value={'name': 'test_proc_name', 'exe': 'test/proc/exec/path', 'pid': 3})

        with patch('utils.psutil.process_iter', MagicMock()) as mock_process_iter:
            mock_process_iter.iter.return_value = iter([mock_proc1, mock_proc2, mock_proc3])

            received_process_instances = list(get_processes_by_name('test_proc_name'))

            self.assertEqual(received_process_instances, [mock_proc3])

请注意,我不是psutil.process_iter直接打补丁,而是将其导入到utils.py定义目标方法的目标模块中。我认为是正确的做法。

在这个测试用例中,我创建了三个模拟进程mock_proc1:第一个(具有所需名称的有效进程。这个想法是,使用方法调用时应该只生成。作为生成器(以下),我遵循了有关如何模拟生成方法的文档。psutil.AccessDeniedas_dictmock_proc2mock_proc3test_proc_nameget_processes_by_nametest_proc_namemock_proc3get_processes_by_namepsutil.process_iterunittest

不幸的是,这个测试用例失败了——目标方法没有生成任何东西,所以断言失败(ipdb下面的输出)。

ipdb> 
> /path/to/tests/test_utils.py(352)test__get_processes_by_name__one_running_proc_matches_given_proc_name__one_proc_instance_generated()
    351 
--> 352             self.assertEqual(received_process_instances, [mock_proc3])
    353 

ipdb> 
AssertionError: Lists differ: [] != [<MagicMock id='4660019536'>]

Second list contains 1 additional elements.
First extra element 0:
<MagicMock id='4660019536'>

我尝试使用ipdb(在目标方法的顶部放置断点)调试目标方法,我可以看到以下输出。

> /path/to/utils.py(183)get_processes_by_name()
    182     import ipdb; ipdb.set_trace()
--> 183     for proc in psutil.process_iter():
    184         try:

ipdb> 
ipdb> n
StopIteration
> /path/to/venv/lib/python3.7/site-packages/pluggy/callers.py(203)_multicall()
    202             try:
--> 203                 gen.send(outcome)
    204                 _raise_wrapfail(gen, "has second yield")

ipdb> 
    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

    [... skipped 1 hidden frame]

我不知道这里发生了什么。是在抱怨中的多个产量psutil.process_iter,还是在嘲笑中存在错误。欢迎大家提出意见。

标签: pythonunit-testingpython-mockpsutil

解决方案


推荐阅读