3. pytest基础入门:安装、运行与断言机制
说实话,我接触pytest之前,一直用unittest写自动化用例。那时候总觉得写个测试怎么这么费劲——类要继承、方法名要特定、断言还得记一堆assertEqual、assertTrue……直到有一天,团队里来了个老哥,看我写测试用例直摇头:「你试试pytest?」
一试,就回不去了。
这一章,我就带你从零开始,把pytest的安装、运行、断言和用例编写规则一次性讲透。都是我在项目中踩过的坑、总结出的经验,你直接拿去用就行。
3.1 安装pytest:比你想象的简单
安装pytest,一句话的事:
pip install pytest
嗯,就这么简单。但我在实际项目中遇到过一个问题——公司内网环境,pip源慢得要命。这时候我建议你加个国内镜像:
pip install pytest -i https://pypi.tuna.tsinghua.edu.cn/simple
装完之后,验证一下:
pytest --version
如果看到版本号,恭喜你,环境搭好了。
python -m venv venv 创建虚拟环境,再激活安装,干净又清爽。
3.2 测试用例编写规则:pytest的「潜规则」
pytest为什么好用?因为它「约定大于配置」。你不需要写一堆样板代码,只要遵守几条简单规则,pytest就能自动发现并执行你的测试用例。
规则其实就三条:
- 文件命名: 测试文件必须以
test_开头,或者以_test结尾。比如test_login.py、login_test.py都行。 - 函数命名: 测试函数必须以
test_开头。比如test_user_login、test_add_item。 - 类命名: 测试类必须以
Test开头,且不能有__init__方法。比如class TestLogin:。
你想想看,这些规则是不是比unittest的「继承TestCase、方法名test开头」要灵活得多?
来看个完整的例子:
# test_demo.py
def test_add_one():
assert 1 + 1 == 2
def test_add_two():
assert 2 + 2 == 4
class TestString:
def test_upper(self):
assert "hello".upper() == "HELLO"
def test_lower(self):
assert "HELLO".lower() == "hello"
保存后,在终端运行:
pytest test_demo.py
pytest会自动找到文件里所有以 test_ 开头的函数和 Test 开头的类中的测试方法,逐个执行。
__init__ 方法。我曾经有个同事,习惯性地在类里加了 __init__,结果pytest死活不执行那个类的用例,排查了半天才发现是这个问题。
3.3 运行pytest:从单文件到批量执行
pytest的运行方式非常灵活。我平时最常用的几种方式,列出来给你参考:
| 命令 | 说明 |
|---|---|
pytest |
运行当前目录及子目录下所有测试文件 |
pytest test_demo.py |
运行指定测试文件 |
pytest test_demo.py::test_add_one |
运行指定测试函数 |
pytest test_demo.py::TestString |
运行指定测试类 |
pytest -k "add" |
运行名称中包含"add"的测试用例 |
pytest -v |
显示详细运行信息(verbose模式) |
pytest -q |
简洁模式,只显示结果 |
我个人最常用的是 pytest -v,因为能看到每个用例的通过/失败状态,排查问题特别方便。
pytest,结果它把项目里所有 test_ 开头的文件都跑了一遍,包括一些废弃的测试脚本,跑了整整20分钟。后来我养成了习惯——要么指定文件,要么在测试目录下运行。
3.4 断言机制:assert 就够了
pytest的断言,说白了就是Python原生的 assert 关键字。不需要记什么 assertEqual、assertTrue,一个 assert 走天下。
来看几个常用场景:
# test_assert.py
def test_equal():
assert 1 + 1 == 2
def test_not_equal():
assert 1 + 1 != 3
def test_in():
assert "hello" in "hello world"
def test_not_in():
assert "xyz" not in "hello world"
def test_true():
assert bool(1) is True
def test_false():
assert bool(0) is False
def test_is_none():
assert None is None
def test_is_not_none():
assert "hello" is not None
你可能会问:「如果断言失败了,pytest会怎么提示?」
这就是pytest厉害的地方了——它会自动分析断言表达式,给出非常详细的失败信息。比如:
def test_fail():
assert 1 + 1 == 3
运行后,pytest会告诉你:
E assert (1 + 1) == 3
E + where 1 + 1 = 2
看到了吗?它不光告诉你断言失败,还帮你算出了实际值是多少。这在排查问题时太有用了。
assert a == b 就行。pytest会递归比较每个元素,失败时还会高亮显示差异部分。我调试接口返回数据时,全靠这个功能快速定位字段差异。
3.5 知识体系总览
下面这张图,是我梳理的pytest基础入门知识结构。你可以把它当作一张「地图」,学完这一章后对照着检查自己掌握了哪些:
3.6 实战小练习:写一个登录测试用例
光说不练假把式。我们结合前面学的知识,写一个简单的登录测试用例:
# test_login.py
def test_login_success():
"""测试登录成功场景"""
username = "admin"
password = "123456"
# 模拟登录验证
result = (username == "admin" and password == "123456")
assert result is True
def test_login_fail_wrong_password():
"""测试密码错误场景"""
username = "admin"
password = "wrong"
result = (username == "admin" and password == "123456")
assert result is False
def test_login_fail_empty_username():
"""测试用户名为空场景"""
username = ""
password = "123456"
result = (username != "" and password == "123456")
assert result is False
运行:
pytest -v test_login.py
你会看到三个用例全部通过。如果故意改错一个断言,pytest会清晰地告诉你哪里出了问题。
assert,没有花哨的API。你只需要关注「业务逻辑是否正确」,剩下的交给pytest去分析。这也是我为什么从unittest转投pytest的原因——少写代码,多关注业务。
好了,这一章的内容就到这里。pytest的安装、运行、断言和用例规则,都是你后续做批量运行和自动化测试的基石。把这些基础打牢,后面学fixture、参数化、conftest.py这些高级特性时,你会觉得水到渠成。
可可精品资料库