写代码写着写着就会发现,测试是个绕不开的话题。可测试代码写得好,bug少一半。不过有些测试真让人头大 - 要么依赖外部API,要么需要复杂的数据库操作。这不,pytest-mock就是来解决这些烦恼的。
1.
模拟测试是啥玩意
说白了就是用假的替代真的。比如你要测试一个发邮件的功能,总不能真发邮件吧?那也太费劲了。用模拟对象来替代真实的邮件发送,既快又稳当。
def send_welcome_email(user_email):
# 假设这是个发邮件的函数
response = send_mail(
to=user_email,
subject=“欢迎加入”,
content=“谢谢注册我们的网站!”
)
return response.status_code == 200
def test_send_welcome_email(mocker):
# 模拟send_mail函数
mock_send = mocker.patch('your_module.send_mail')
mock_send.return_value.status_code = 200
result = send_welcome_email('test@example.com')
assert result == True
2.
mocker.patch 这个法宝
mocker.patch是最常用的一招。它能替换掉原来的函数或类,让你想返回啥就返回啥。
def test_database_query(mocker):
mock_db = mocker.patch('database.query')
mock_db.return_value = {'name': '张三', 'age': 18}
result = get_user_info(1) # 这个函数内部会调用database.query
assert result['name'] == '张三'
温馨提示:模拟对象记得放在测试函数里面,别放外面,不然可能串味儿。
3.
监视函数调用
有时候不光要模拟返回值,还想知道这函数到底被谁调了,参数是啥。
def test_log_error(mocker):
mock_logger = mocker.patch('utils.logger.error')
process_data({'invalid': 'data'})
# 检查是否调用了error方法,参数是啥
mock_logger.assert_called_once_with('数据格式不正确')
4.
模拟异常情况
代码测试不能光测试正常情况,异常处理也得覆盖到。pytest-mock能帮你轻松模拟各种异常。
def test_api_timeout(mocker):
mock_request = mocker.patch('requests.get')
mock_request.side_effect = TimeoutError('连接超时')
try:
fetch_data('http://api.example.com')
except TimeoutError as e:
assert str(e) == '连接超时'
5.
实用小技巧
用mock写测试有几个坑,提前跟大家说说:
路径要写对,模拟的时候要写被调用的地方,不是调用的地方
记得用mocker.patch返回的mock对象,别自己瞎new
别嵌套太深的mock,测试代码越简单越好
mocker.patch('app.services.utils.helper.function')
# 好的写法
mocker.patch('app.services.get_data') # 直接mock最外层调用
6.
连环mock也不怕
有时候一个测试要模拟好几个东西,pytest-mock也不含糊:
def test_complex_scenario(mocker):
mock_notification = mocker.patch('notify.send')
process_user_data(1)
mock_notification.assert_called_once()
写测试代码确实费事,但是有了pytest-mock,测试写起来顺手多了。代码质量上去了,晚上睡觉也踏实。记住一点,测试代码也是代码,该整理的时候还得整理,不能乱糟糟的。
· END ·
欢迎分享到朋友圈
MU MU MA
领取专属 10元无门槛券
私享最新 技术干货