rob*_*ill 3 python mocking pytest
我在使用 pytest-mock 和模拟 open 时遇到问题。
我想测试的代码如下所示:
import re
import os
def get_uid():
regex = re.compile('Serial\s+:\s*(\w+)')
uid = "NOT_DEFINED"
exists = os.path.isfile('/proc/cpuinfo')
if exists:
with open('/proc/cpuinfo', 'r') as file:
cpu_details = file.read()
uid = regex.search(cpu_details).group(1)
return uid
Run Code Online (Sandbox Code Playgroud)
所以测试文件是:
import os
import pytest
from cpu_info import uid
@pytest.mark.usefixtures("mocker")
class TestCPUInfo(object):
def test_no_proc_cpuinfo_file(self):
mocker.patch(os.path.isfile).return_value(False)
result = uid.get_uid()
assert result == "NOT_FOUND"
def test_no_cpu_info_in_file(self):
file_data = """
Hardware : BCM2835
Revision : a020d3
"""
mocker.patch('__builtin__.open', mock_open(read_data=file_data))
result = uid.get_uid()
assert result == "NOT_DEFINED"
def test_cpu_info(self):
file_data = """
Hardware : BCM2835
Revision : a020d3
Serial : 00000000e54cf3fa
"""
mocker.patch('__builtin__.open', mock_open(read_data=file_data))
result = uid.get_uid()
assert result == "00000000e54cf3fa"
Run Code Online (Sandbox Code Playgroud)
测试运行给出:
pytest
======================================= test session starts ========================================
platform linux -- Python 3.5.3, pytest-4.4.1, py-1.8.0, pluggy-0.9.0
rootdir: /home/robertpostill/software/gateway
plugins: mock-1.10.4
collected 3 items
cpu_info/test_cpu_info.py FFF [100%]
============================================= FAILURES =============================================
______________________________ TestCPUInfo.test_no_proc_cpuingo_file _______________________________
self = <test_cpu_info.TestCPUInfo object at 0x75e6eaf0>
def test_no_proc_cpuingo_file(self):
> mocker.patch(os.path.isfile).return_value(False)
E NameError: name 'mocker' is not defined
cpu_info/test_cpu_info.py:9: NameError
___________________________________ TestCPUInfo.test_no_cpu_info ___________________________________
self = <test_cpu_info.TestCPUInfo object at 0x75e69d70>
def test_no_cpu_info(self):
file_data = """
Hardware : BCM2835
Revision : a020d3
"""
> mocker.patch('__builtin__.open', mock_open(read_data=file_data))
E NameError: name 'mocker' is not defined
cpu_info/test_cpu_info.py:18: NameError
____________________________________ TestCPUInfo.test_cpu_info _____________________________________
self = <test_cpu_info.TestCPUInfo object at 0x75e694f0>
def test_cpu_info(self):
file_data = """
Hardware : BCM2835
Revision : a020d3
Serial : 00000000e54cf3fa
"""
> mocker.patch('__builtin__.open', mock_open(read_data=file_data))
E NameError: name 'mocker' is not defined
cpu_info/test_cpu_info.py:28: NameError
===================================== 3 failed in 0.36 seconds =====================================
Run Code Online (Sandbox Code Playgroud)
我认为我已经正确地声明了模拟装置,但它似乎不是......我做错了什么?
在您的测试中模拟使用并没有太多问题。其实只有两个:
mocker夹具如果您需要访问夹具的返回值,请将其名称包含在测试函数参数中,例如:
class TestCPUInfo:
def test_no_proc_cpuinfo_file(self, mocker):
mocker.patch(...)
Run Code Online (Sandbox Code Playgroud)
pytest运行测试时将自动将测试参数值映射到固定装置值。
mocker.patchmocker.patch只是一个垫片unittest.mock.patch,仅此而已;它的存在只是为了方便,这样您就不必到处导入unittest.mock.patch。这意味着它mocker.patch具有相同的签名,unittest.mock.patch并且当您怀疑是否正确使用它时,您可以随时查阅 stdlib 的文档。
在你的情况下,mocker.patch(os.path.isfile).return_value(False)这不是方法的正确用法patch。来自文档:
target应该是 形式的字符串
'package.module.ClassName'。...
patch()接受任意关键字参数。这些将被传递给Mock(或new_callable) 进行构建。
这意味着该行
mocker.patch(os.path.isfile).return_value(False)
Run Code Online (Sandbox Code Playgroud)
应该
mocker.patch('os.path.isfile', return_value=False)
Run Code Online (Sandbox Code Playgroud)
现在剩下的就是与您的实现有关的错误;您必须调整测试以测试正确的行为或修复实现错误。
例子:
assert result == "NOT_FOUND"
Run Code Online (Sandbox Code Playgroud)
总是会引发,因为"NOT_FOUND"代码中甚至不存在。
assert result == "NOT_DEFINED"
Run Code Online (Sandbox Code Playgroud)
总是会引发,因为uid = "NOT_DEFINED"总是会被正则表达式搜索结果覆盖,因此永远不会返回。
假设您的测试是唯一的事实来源,我修复了上述模拟用法的两个错误,并调整了实现get_uid()以使测试通过:
import os
import re
def get_uid():
regex = re.compile(r'Serial\s+:\s*(\w+)')
exists = os.path.isfile('/proc/cpuinfo')
if not exists:
return 'NOT_FOUND'
with open('/proc/cpuinfo', 'r') as file:
cpu_details = file.read()
match = regex.search(cpu_details)
if match is None:
return 'NOT_DEFINED'
return match.group(1)
Run Code Online (Sandbox Code Playgroud)
测试:
import pytest
import uid
class TestCPUInfo:
def test_no_proc_cpuinfo_file(self, mocker):
mocker.patch('os.path.isfile', return_value=False)
result = uid.get_uid()
assert result == "NOT_FOUND"
def test_no_cpu_info_in_file(self, mocker):
file_data = """
Hardware : BCM2835
Revision : a020d3
"""
mocker.patch('builtins.open', mocker.mock_open(read_data=file_data))
result = uid.get_uid()
assert result == "NOT_DEFINED"
def test_cpu_info(self, mocker):
file_data = """
Hardware : BCM2835
Revision : a020d3
Serial : 00000000e54cf3fa
"""
mocker.patch('builtins.open', mocker.mock_open(read_data=file_data))
result = uid.get_uid()
assert result == "00000000e54cf3fa"
Run Code Online (Sandbox Code Playgroud)
请注意,我使用的是 Python 3,因此我无法修补__builtin__并诉诸修补builtins;除此之外,代码应该与 Python 2 变体相同。另外,由于mocker无论如何都使用了 ,所以我使用了mocker.mock_open,从而节省了额外导入unittest.mock.mock_open.
| 归档时间: |
|
| 查看次数: |
6181 次 |
| 最近记录: |