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()

核心要点:

  1. 使用side_effect属性:这是mock异常的关键,可以设置为异常类或异常实例
  2. 三种常用方式
    • 直接设置异常:mock.side_effect = SomeException("message")
    • 使用函数动态决定:通过函数根据参数决定是否抛出
    • 使用装饰器或上下文管理器:@patchwith 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 的例子

回到顶部