Python 模拟:为单元测试引发第 3 方异常
Python Mock: raise 3rd party exception for unit testing
假设我有一个方法 is_validate
,它在内部调用库 gateway.service
中的 validate
方法
import gateway.service
from gateway.service.exception import ValidatorException
def is_validate():
try:
gateway.service.validate() # which throws ValidatorException
return True
except ValidatorException ex:
return False
如何对is_validate
方法进行单元测试,模拟gateway.service.validate
抛出ValidatorException
?
您可以通过以下组合来做到这一点:
- 模拟一个函数(创建一个伪造的函数版本来指示它returns);
monkeypatch
使用模拟版本实现实际功能;
- 并使用
pytest
实际 运行 测试。
我已经写了一篇关于如何做到这一点的描述(摘自我自己的作品)here,以防我知道有用的例子。
但我认为您需要在代码中这样做:
定义一个 pytest fixture 来模拟你想要测试的场景,使用 monkeypatch 从 is_validate()
.
的部分伪造你想要的结果
以及检查是否引发 ValidatorException 的测试;在测试中引发错误的代码在 pytest 夹具中。那里定义的整个 pytest fixture 作为参数传递给测试。
import pytest
from unittest import TestCase
import gateway.service
from gateway.service.exception import ValidatorException
# Create object for accessing unittest assertions
assertions = TestCase("__init__")
@pytest.fixture
def validation_fails(monkeypatch):
"""
Mocks a call to gateway.service.validate().
"""
def mock_validate(*args, **kwargs):
"""Mock an absolute file path."""
raise ValidatorException
# Replace calls to existing methods with the mocked versions
monkeypatch.setattr(gateway.service, "validate", mock_validate)
def test_validation_fails(validation_fails):
"""Test validation."""
# check that the correct exception is raised
with assertions.assertRaises(ValidatorException):
is_validate()
注意:这不包括让 pytest
为您的项目工作所需的任何设置。
-------------------------------------
mymodule.py
-------------------------------------
import os
def remove(file_path):
if os.path.exists(file_path):
os.remove(file_path)
else:
print('File does not exist')
-------------------------------------
from mymodule import remove
import mock
import unittest
class RemoveTestCase(unittest.TestCase):
@mock.patch('mymodule.os.path')
@mock.patch('mymodule.os.remove')
def test_remove(self, mock_os_remove, mock_os_path):
mock_os_path.exists.return_value = True
#side_effect
remove("any path")
mock_os_remove.assert_called_with("any path")
我能够通过使用存在 is_validate
方法的模块名称引用它来模拟 gateway.service.validate
。
例如:@mock.patch('mymodule.gateway.service.validate')
参考此 doc 了解更多信息
假设我有一个方法 is_validate
,它在内部调用库 gateway.service
validate
方法
import gateway.service
from gateway.service.exception import ValidatorException
def is_validate():
try:
gateway.service.validate() # which throws ValidatorException
return True
except ValidatorException ex:
return False
如何对is_validate
方法进行单元测试,模拟gateway.service.validate
抛出ValidatorException
?
您可以通过以下组合来做到这一点:
- 模拟一个函数(创建一个伪造的函数版本来指示它returns);
monkeypatch
使用模拟版本实现实际功能;- 并使用
pytest
实际 运行 测试。
我已经写了一篇关于如何做到这一点的描述(摘自我自己的作品)here,以防我知道有用的例子。
但我认为您需要在代码中这样做:
定义一个 pytest fixture 来模拟你想要测试的场景,使用 monkeypatch 从 is_validate()
.
以及检查是否引发 ValidatorException 的测试;在测试中引发错误的代码在 pytest 夹具中。那里定义的整个 pytest fixture 作为参数传递给测试。
import pytest
from unittest import TestCase
import gateway.service
from gateway.service.exception import ValidatorException
# Create object for accessing unittest assertions
assertions = TestCase("__init__")
@pytest.fixture
def validation_fails(monkeypatch):
"""
Mocks a call to gateway.service.validate().
"""
def mock_validate(*args, **kwargs):
"""Mock an absolute file path."""
raise ValidatorException
# Replace calls to existing methods with the mocked versions
monkeypatch.setattr(gateway.service, "validate", mock_validate)
def test_validation_fails(validation_fails):
"""Test validation."""
# check that the correct exception is raised
with assertions.assertRaises(ValidatorException):
is_validate()
注意:这不包括让 pytest
为您的项目工作所需的任何设置。
-------------------------------------
mymodule.py
-------------------------------------
import os
def remove(file_path):
if os.path.exists(file_path):
os.remove(file_path)
else:
print('File does not exist')
-------------------------------------
from mymodule import remove
import mock
import unittest
class RemoveTestCase(unittest.TestCase):
@mock.patch('mymodule.os.path')
@mock.patch('mymodule.os.remove')
def test_remove(self, mock_os_remove, mock_os_path):
mock_os_path.exists.return_value = True
#side_effect
remove("any path")
mock_os_remove.assert_called_with("any path")
我能够通过使用存在 is_validate
方法的模块名称引用它来模拟 gateway.service.validate
。
例如:@mock.patch('mymodule.gateway.service.validate')
参考此 doc 了解更多信息