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

如果看到版本号,恭喜你,环境搭好了。

小提示: 我个人习惯用虚拟环境装pytest,避免污染全局Python。用 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基础入门知识结构。你可以把它当作一张「地图」,学完这一章后对照着检查自己掌握了哪些:

pytest基础入门 安装与验证 pip install pytest pytest --version 用例编写规则 文件: test_*.py / *_test.py 函数: def test_*() 类: class Test* (无__init__) 运行方式 pytest (全部) pytest -v (详细模式) pytest -k "关键字" 断言机制 assert 表达式 (原生Python) 自动分析失败原因,显示实际值

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会清晰地告诉你哪里出了问题。

核心要点: pytest的断言就是 assert,没有花哨的API。你只需要关注「业务逻辑是否正确」,剩下的交给pytest去分析。这也是我为什么从unittest转投pytest的原因——少写代码,多关注业务。

好了,这一章的内容就到这里。pytest的安装、运行、断言和用例规则,都是你后续做批量运行和自动化测试的基石。把这些基础打牢,后面学fixture、参数化、conftest.py这些高级特性时,你会觉得水到渠成。

可可精品资料库