为什么需要Mock统计方法
在单元测试中,Mock对象允许我们模拟依赖项的行为。统计方法帮助我们验证:
- 模拟方法是否被调用
- 方法被调用的次数
- 调用时使用的参数
- 不同调用之间的差异
这些验证对于确保代码按预期执行至关重要。
核心统计方法
1. called - 是否被调用
检查Mock对象是否被调用过
import unittest
from unittest.mock import Mock
def test_called(self):
mock = Mock()
mock() # 调用mock对象
self.assertTrue(mock.called)
2. call_count - 调用次数
记录Mock对象被调用的总次数
def test_call_count(self):
mock = Mock()
mock()
mock()
self.assertEqual(mock.call_count, 2)
3. call_args - 最后一次调用参数
获取最后一次调用时使用的参数
def test_call_args(self):
mock = Mock()
mock(1, 2, 3, a=4, b=5)
self.assertEqual(mock.call_args.args, (1, 2, 3))
self.assertEqual(mock.call_args.kwargs, {'a': 4, 'b': 5})
4. call_args_list - 所有调用参数
获取所有调用的参数列表
def test_call_args_list(self):
mock = Mock()
mock(1)
mock(2, 3)
mock(a=4)
calls = [call(1), call(2, 3), call(a=4)]
self.assertEqual(mock.call_args_list, calls)
5. method_calls - 方法调用记录
记录Mock对象上所有方法的调用
def test_method_calls(self):
mock = Mock()
mock.method_a(1)
mock.method_b(2, 3)
expected_calls = [
call.method_a(1),
call.method_b(2, 3)
]
self.assertEqual(mock.method_calls, expected_calls)
高级统计技巧
使用assert_called_with验证调用
def test_assert_called_with(self):
mock = Mock()
mock(1, 2, a=3)
mock.assert_called_with(1, 2, a=3)
使用assert_called_once_with验证单次调用
def test_assert_called_once_with(self):
mock = Mock()
mock(1)
mock.assert_called_once_with(1)
mock(2) # 第二次调用
# 下面会失败,因为调用了两次
# mock.assert_called_once_with(2)
使用assert_has_calls验证调用顺序
def test_assert_has_calls(self):
mock = Mock()
mock(1)
mock(2)
mock(3)
# 验证调用顺序
mock.assert_has_calls([call(1), call(2), call(3)])
# 验证调用存在,忽略顺序
mock.assert_has_calls([call(3), call(1)], any_order=True)
实际应用示例
测试用户注册服务
class UserService:
def __init__(self, db, email_service):
self.db = db
self.email_service = email_service
def register_user(self, name, email):
user_id = self.db.save_user(name, email)
self.email_service.send_welcome_email(email)
return user_id
class TestUserService(unittest.TestCase):
def test_registration_flow(self):
# 创建Mock依赖
db_mock = Mock()
email_mock = Mock()
# 设置模拟返回值
db_mock.save_user.return_value = 123
# 创建服务实例
service = UserService(db_mock, email_mock)
user_id = service.register_user("John", "john@example.com")
# 验证调用
self.assertEqual(user_id, 123)
db_mock.save_user.assert_called_once_with("John", "john@example.com")
email_mock.send_welcome_email.assert_called_once_with("john@example.com")
self.assertEqual(db_mock.save_user.call_count, 1)
最佳实践总结
精确验证
使用assert_called_with等具体断言替代手动检查call_count和call_args,使测试更清晰明确。
避免过度验证
只验证与测试目标相关的交互,不要过度测试Mock对象的内部细节。
组合使用
结合多种统计方法进行全面验证:
- 验证调用次数 + 参数
- 验证调用顺序 + 参数值
清理Mock状态
在测试之间重置Mock对象,避免状态泄漏:
def setUp(self):
self.mock = Mock()
发表评论