头像
淇迹时刻
-- : -- : --
切换主题色
-- : -- : --

第四阶段:Mock技术与代码覆盖率

最后更新于:

第四阶段:Mock技术与代码覆盖率

一、Mock技术

1.1 什么是Mock?

Mock是一种测试技术,用于隔离被测代码与外部依赖,使测试更加可靠和快速。

场景示例

  • 测试一个调用数据库的函数,不想真的连接数据库
  • 测试一个调用外部API的函数,不想真的发送HTTP请求
  • 测试一个调用时间相关函数的代码,想控制时间返回值

1.2 unittest.mock基础

Python标准库unittest.mock提供了Mock功能,pytest-mock插件使其使用更加方便。

1.3 Mock对象的基本用法

1from unittest.mock import Mock
2
3mock_obj = Mock()
4mock_obj.some_method.return_value = 42
5result = mock_obj.some_method()
6assert result == 42

1.4 Mock的常用方法和属性

方法/属性说明示例
return_value设置方法返回值mock.get.return_value = {"data": "test"}
side_effect设置方法执行效果mock.get.side_effect = Exception("Network error")
call_args获取调用参数mock.get.call_args == (("url",), {"timeout": 10})
called判断是否被调用assert mock.get.called
call_count获取调用次数assert mock.get.call_count == 2
reset_mock()重置Mock状态mock.get.reset_mock()

1.5 使用@pytest.mark.mocker

1def test_with_mocker(mocker):
2    mock_get = mocker.patch("requests.get")
3    mock_get.return_value.json.return_value = {"data": "test"}
4    # 测试代码

1.6 使用@patch装饰器

1from unittest.mock import patch
2
3@patch("requests.get")
4def test_with_decorator(mock_get):
5    mock_get.return_value.json.return_value = {"data": "test"}
6    # 测试代码

1.7 Mock类依赖

1def test_with_mocked_class():
2    mock_service = Mock()
3    mock_service.get_user.return_value = {"id": 1, "name": "Test"}
4    
5    service = OrderService(mock_service)
6    result = service.create_order(1, items)
7    assert result["user_name"] == "Test"

二、代码覆盖率

2.1 什么是代码覆盖率?

代码覆盖率是衡量测试用例覆盖源代码程度的指标,通常以百分比表示。

2.2 覆盖率类型

类型说明
Line Coverage行覆盖率:有多少行代码被执行
Branch Coverage分支覆盖率:有多少条件分支被执行
Function Coverage函数覆盖率:有多少函数被调用
Statement Coverage语句覆盖率:有多少语句被执行

2.3 使用pytest-cov

 1# 安装插件
 2pip install pytest-cov
 3
 4# 统计代码覆盖率
 5pytest --cov=src --cov-report=html
 6
 7# 查看未覆盖的代码行
 8pytest --cov=src --cov-report=term-missing
 9
10# 生成覆盖率报告
11pytest --cov=src --cov-report=html --cov-report=xml

2.4 覆盖率配置

pytest.ini中配置覆盖率:

1[pytest]
2addopts = --cov=src --cov-report=term-missing

2.5 排除文件

1pytest --cov=src --cov-exclude="src/__init__.py" --cov-exclude="src/config.py"

三、示例代码

3.1 Mock示例

 1# tests/test_user_service.py
 2import pytest
 3from src.user_service import UserService
 4
 5def test_get_user_success(mocker):
 6    mock_get = mocker.patch("requests.get")
 7    mock_response = Mock()
 8    mock_response.status_code = 200
 9    mock_response.json.return_value = {"id": 1, "name": "Test User"}
10    mock_get.return_value = mock_response
11
12    service = UserService("https://api.example.com")
13    result = service.get_user(1)
14
15    assert result == {"id": 1, "name": "Test User"}
16    mock_get.assert_called_once_with("https://api.example.com/users/1")

3.2 Mock类依赖示例

 1# tests/test_order_service.py
 2import pytest
 3from unittest.mock import Mock
 4from src.order_service import OrderService
 5
 6def test_create_order_success(mock_user_service):
 7    mock_user_service.get_user.return_value = {"id": 1, "name": "Test User"}
 8    
 9    service = OrderService(mock_user_service)
10    items = [{"name": "Item 1", "price": 100}]
11    order = service.create_order(1, items)
12
13    assert order["user_id"] == 1
14    assert order["user_name"] == "Test User"

3.3 被测代码示例

 1# src/user_service.py
 2import requests
 3
 4class UserService:
 5    def __init__(self, api_url):
 6        self.api_url = api_url
 7
 8    def get_user(self, user_id):
 9        response = requests.get(f"{self.api_url}/users/{user_id}")
10        if response.status_code == 200:
11            return response.json()
12        else:
13            return None
14
15    def create_user(self, user_data):
16        response = requests.post(f"{self.api_url}/users", json=user_data)
17        if response.status_code == 201:
18            return response.json()
19        else:
20            raise ValueError(f"Failed to create user: {response.status_code}")

四、易错点与注意事项

4.1 Mock常见错误

  1. patch路径错误:patch的路径必须是被测代码中实际导入的路径
  2. Mock对象方法未调用:忘记调用被Mock的方法
  3. Mock返回值设置错误:设置了错误的返回值结构
  4. 忘记重置Mock:在多个测试中共享Mock对象时需要重置

4.2 覆盖率常见错误

  1. 覆盖率过高追求:100%覆盖率不是目标,代码质量才是
  2. 测试不充分:覆盖了代码但没有测试实际逻辑
  3. 排除过多:排除了重要的业务代码
  4. 忽略分支覆盖:只关注行覆盖,忽略条件分支

4.3 最佳实践

  1. Mock外部依赖,不Mock被测代码
  2. 使用assert_called_once_with()验证调用参数
  3. 合理设置覆盖率目标(如80%以上)
  4. 定期检查覆盖率报告,补充缺失的测试

五、小结

本阶段学习了Mock技术和代码覆盖率,包括:

  • unittest.mock的基本用法
  • pytest-mock插件的使用
  • Mock对象的常用属性和方法
  • 代码覆盖率的统计和分析
  • 覆盖率报告的生成
最新文章