一、pytest及其特点
1. 什么是pytest
pytest
是一个功能强大且灵活的 Python 测试框架,也是目前最流行的测试框架,可以让我们很方便的编写和管理自动化测试用例,并提供丰富的插件来满足单元测试、集成测试、性能测试等各种测试需求。
2. pytest的特点
- 简洁的语法:使用
pytest
编写测试代码非常简洁,只需使用assert
语句进行断言。 - 自动发现测试:
pytest
可以自动发现测试用例并执行,而无需手动指定每个测试的运行顺序。 - 支持多种测试类型:除了基本的单元测试,
pytest
还支持参数化测试、性能测试、集成测试等。 - 丰富的插件支持:
pytest
拥有众多插件,支持例如代码覆盖率、并行测试、mock 测试等功能。 - 易于扩展:你可以通过编写自定义插件和钩子来扩展
pytest
的功能。 - 强大的断言功能:
pytest
的断言失败时,会提供详细的错误信息,便于定位问题。
相比于 unittest(也是测试框架,需要通过继承 unittest.TestCase
来编写测试用例),pytest不用继承什么类来编写和管理测试用例,更加的方便。
二、常见语法和用法
以下是 pytest
的一些常见语法和用法:
1. 基本测试语法
在 pytest
中,当我们运行测试用例时,它会自动识别 以test_
开头的函数并运行该函数,所以我们在用pytest管理测试用例时,函数名一般都是以test_
开头的,一个简单的测试用例如下:
#包含头文件
import pytestdef test_addition():assert 1 + 1 == 2
assert
是 Python 的断言语句,用来检查表达式是否为真。如果为假,测试会失败。
2. 运行测试
-
运行所有的测试:
pytest
以VScode(一个编写代码的软件)为例子如下图
-
要运行一个测试文件下的测试用例我们要在pytest后面加上文件名,如果要是想运行不同文件夹下的文件可以用相对路径来实现。如下
pytest test_file.py
pytest ./testcase/test_file1
-
使用
-v
来获取更详细的输出:
pytest -v
3. 断言
pytest
提供了强大的断言机制。当断言失败时,它会自动输出失败的原因,并且比原生的 assert
语句更为直观。例如:
def test_addition():assert 1 + 1 == 2 # 断言表达式是否为真assert 1 + 2 == 3
如果失败,pytest
会显示错误的表达式和值:
AssertionError: assert 3 == 4
4. 使用 Fixture 进行预处理
pytest
提供了 fixture
用于测试前的数据准备、初始化等操作。使用 @pytest.fixture
装饰器来定义一个 fixture。
import pytest# 定义一个 fixture
@pytest.fixture
def sample_data():return [1, 2, 3]def test_sum(sample_data):assert sum(sample_data) == 6
sample_data
这个 fixture 会在 test_sum
测试函数执行之前自动提供。,相当于sample_data=[1,2,3]。
5. 测试的组织结构
pytest
允许你按照不同的级别组织测试,例如按函数、类、模块、会话等来划分。可以通过 scope
来设置 fixture 的作用范围。
@pytest.fixture(scope="module")
def database_connection():# 在模块级别初始化数据库连接return DatabaseConnection()def test_query1(database_connection):assert database_connection.query("SELECT 1") == 1def test_query2(database_connection):assert database_connection.query("SELECT 2") == 2
scope="function"
:每个测试函数都会调用一次 fixture(默认值)。scope="module"
:每个模块只会调用一次 fixture。scope="class"
:每个测试类只会调用一次 fixture。scope="session"
:整个测试会话期间只会调用一次 fixture。
6. 跳过和预期失败的测试
pytest
允许你跳过某些测试,或标记为预期失败(即测试本身已经是失败状态,仍然执行)。
跳过测试
使用 @pytest.mark.skip
或 @pytest.mark.skipif
来跳过测试。
import pytest@pytest.mark.skip(reason="此测试暂时跳过")
def test_not_ready():assert False # 这个测试会被跳过
条件跳过
@pytest.mark.skipif(condition=True, reason="条件为真时跳过")
def test_skip_if():assert False
预期失败
使用 @pytest.mark.xfail
标记某个测试为预期失败。如果测试失败,pytest
会将它视为通过。
@pytest.mark.xfail
def test_expected_fail():assert 1 + 1 == 3 # 预期失败
7. 参数化测试
使用 @pytest.mark.parametrize
可以方便地将同一个测试函数参数化,传入多个不同的输入值进行多次测试。
import pytest@pytest.mark.parametrize("a, b, expected", [(1, 1, 2),(2, 2, 4),(3, 3, 6)
])
def test_add(a, b, expected):assert a + b == expected
这将自动运行三个测试用例,分别是 (1, 1, 2)
、(2, 2, 4)
和 (3, 3, 6)
。
8. 自定义标记
pytest
支持自定义标记来分类测试。例如,我们可以创建一个标记来标识慢测试。
import pytest@pytest.mark.slow
def test_long_running():assert True
运行时,使用 -m
选项来只运行带有特定标记的测试:
pytest -m slow
9. 命令行选项
pytest
提供了很多命令行选项来控制测试行为:
-v
:显示详细的测试结果。-q
:简洁输出。--maxfail
:最多失败多少个测试时停止执行。-k
:只运行匹配指定表达式的测试。
例如,运行所有带有 test_add
名称的测试:
pytest -k test_add
10. 日志记录
pytest
可以集成 Python 的日志记录系统,通过 caplog
捕获日志输出。
import loggingdef test_log(caplog):logger = logging.getLogger("test_logger")logger.warning("This is a warning message")# 捕获日志并验证assert "This is a warning message" in caplog.text
11. 使用 pytest
的插件
pytest
具有丰富的插件生态,常用的插件包括:
pytest-cov
:用于代码覆盖率测试。pytest-xdist
:用于并行测试。pytest-mock
:用于模拟(mock)对象。
通过 pip
安装插件:
pip install pytest-cov
然后在运行时指定插件选项:
pytest --cov=my_module