Python中如何mock一个异常并抛出?
看下面的例子:
class TestService(unittest.TestCase):
def test_raise(self):
class MyException(BaseException):
pass
mockedException = mock.create_autospec(spec=MyException, instance=True)
self.assertIsInstance(mockedException, BaseException)
raise mockedException
输出:TypeError: exceptions must derive from BaseException 大意是:抛出的异常对象必须是继承自 BaseException
在实际环境中,这个需要 mock 的异常类是一个抽象基类。我使其继承自 abc.ABC 和 Exception 当然,实际实现一个子类,然后在单元测试中使用这个子类,即可通过。但个人觉得这比较 low
Python中如何mock一个异常并抛出?
3 回复
import unittest
from unittest.mock import patch
import some_module # 假设这是你要测试的模块
class TestExceptionMocking(unittest.TestCase):
def test_mock_exception_raising(self):
# 方法1: 使用patch.object直接替换方法
with patch.object(some_module.SomeClass, 'some_method') as mock_method:
# 设置side_effect为要抛出的异常
mock_method.side_effect = ValueError("模拟的异常信息")
# 调用被mock的方法时会抛出异常
with self.assertRaises(ValueError) as context:
some_module.SomeClass().some_method()
# 验证异常信息
self.assertEqual(str(context.exception), "模拟的异常信息")
def test_mock_function_exception(self):
# 方法2: 使用patch装饰器mock函数
@patch('some_module.some_function')
def test_func(mock_func):
mock_func.side_effect = RuntimeError("函数执行失败")
with self.assertRaises(RuntimeError):
some_module.some_function()
test_func()
def test_mock_with_specific_args(self):
# 方法3: 根据参数决定是否抛出异常
def side_effect_func(arg):
if arg == "error":
raise TypeError("参数错误")
return "正常结果"
with patch.object(some_module.SomeClass, 'method') as mock_method:
mock_method.side_effect = side_effect_func
# 正常调用
result = some_module.SomeClass().method("normal")
self.assertEqual(result, "正常结果")
# 会抛出异常的调用
with self.assertRaises(TypeError):
some_module.SomeClass().method("error")
if __name__ == '__main__':
unittest.main()
核心要点:
- 使用
side_effect属性:这是mock异常的关键,可以设置为异常类或异常实例 - 三种常用方式:
- 直接设置异常:
mock.side_effect = SomeException("message") - 使用函数动态决定:通过函数根据参数决定是否抛出
- 使用装饰器或上下文管理器:
@patch或with patch()
- 直接设置异常:
实际示例:
# 假设要测试这个函数
def process_data(data):
if not data:
raise ValueError("数据不能为空")
return data.upper()
# 测试代码
from unittest.mock import Mock
def test_process_data():
# 模拟一个会抛出异常的对象
bad_data = Mock()
bad_data.__bool__ = Mock(return_value=False) # 模拟空数据
with patch('__main__.process_data') as mock_process:
mock_process.side_effect = ValueError("数据不能为空")
import pytest
with pytest.raises(ValueError) as exc_info:
process_data(bad_data)
assert "数据不能为空" in str(exc_info.value)
一句话总结:用side_effect属性mock异常,配合assertRaises验证。
这官方文档上都有啊, 用 side_effect
https://docs.python.org/3/library/unittest.mock.html
还有 unittest 的文档 https://docs.python.org/3/library/unittest.html 一开头就举了个 asseetRaises 的例子

