文章目录
-
-
- [1. 文件及用例命名规范](#1. 文件及用例命名规范)
- [2. 常用的断言类型](#2. 常用的断言类型)
- [3. 指定目录与文件执行用例](#3. 指定目录与文件执行用例)
- [4. 运行参数 `-m` 和 `-k`](#4. 运行参数
-m和-k) - [5. 使用 `pytest.ini` 配置文件](#5. 使用
pytest.ini配置文件) - [6. setup 和 teardown 详解](#6. setup 和 teardown 详解)
- [7. 测试用例执行顺序](#7. 测试用例执行顺序)
- [8. skip 和 skipif:测试用例跳过](#8. skip 和 skipif:测试用例跳过)
- [9. 解决接口参数依赖 (结合 pytest + requests 练习)](#9. 解决接口参数依赖 (结合 pytest + requests 练习))
-
1. 文件及用例命名规范
pytest 默认会有一套自动发现测试用例的规则。只有符合规则的文件和函数,才会被执行。
- 测试文件 :必须以
test_*.py开头或*_test.py结尾。 - 测试类 :必须以
Test开头,且不能包含__init__方法。 - 测试函数/方法 :必须以
test_开头。
2. 常用的断言类型
与 Python 自带的 unittest 需要使用 assertEqual、assertTrue 不同,pytest 直接使用 Python 原生的 assert 关键字即可。
python
def test_assertions():
assert 1 + 1 == 2 # 判断相等
assert "test" in "pytest" # 判断包含
assert 3 > 2 # 判断大小
assert True # 判断真假
3. 指定目录与文件执行用例
在命令行中,你可以灵活指定要运行的测试范围:
- 运行所有用例 :在项目根目录下直接输入
pytest - 运行指定目录 :
pytest tests/(运行 tests 文件夹下的所有用例) - 运行指定文件 :
pytest test_api.py - 运行指定函数 :
pytest test_api.py::test_login
4. 运行参数 -m 和 -k
这两个参数用于在海量用例中过滤出你想执行的用例。
-
-k(关键字匹配) :运行名称中包含指定字符串的用例。bashpytest -k "login or register" # 运行名字中包含 login 或 register 的用例 -
-m(标记匹配) :运行带有特定自定义标记(如@pytest.mark.smoke)的用例。bashpytest -m "smoke" # 运行被打上 smoke 标签的冒烟测试用例
5. 使用 pytest.ini 配置文件
为了避免每次都在命令行输入一长串参数,可以将配置写在项目根目录的 pytest.ini 文件中。
ini
[pytest]
# 配置默认运行参数 (例如:-v 打印详细信息, -s 打印控制台输出)
addopts = -v -s -m "smoke"
# 配置 pytest 寻找用例的默认目录 (testpaths)
testpaths = ./tests
# 注册自定义标记,消除警告
markers =
smoke: 冒烟测试
api: 接口测试
6. setup 和 teardown 详解
用于在测试执行前进行环境初始化(如建立数据库连接),测试后进行环境清理(如清除脏数据)。pytest 支持多个级别的 setup/teardown:
- 模块级 (Module) :
setup_module()/teardown_module(),在整个.py文件前后执行一次。 - 类级 (Class) :
setup_class()/teardown_class(),在整个测试类前后执行一次。 - 方法/函数级 (Method/Function) :
setup_method()/teardown_method(),在每个用例前后都会执行。
python
import pytest
# ================= 1. 模块级 (Module Level) =================
# 针对整个 .py 文件,在所有用例开始前和结束后各运行一次
def setup_module():
print("\n【模块级】setup_module:整个文件开始执行。(例如:建立全局数据库连接)")
def teardown_module():
print("\n【模块级】teardown_module:整个文件执行完毕。(例如:断开全局数据库连接)")
# ================= 2. 函数级 (Function Level) =================
# 针对类外部的测试函数,在每个测试函数前后都会运行
def setup_function():
print("\n [函数级] setup_function:准备执行类外部的测试函数。(例如:准备测试数据)")
def teardown_function():
print(" [函数级] teardown_function:类外部的测试函数执行完毕。(例如:清理测试数据)")
def test_outside_func_1():
print(" -> 正在执行测试函数: test_outside_func_1")
assert 1 + 1 == 2
def test_outside_func_2():
print(" -> 正在执行测试函数: test_outside_func_2")
assert True
# ================= 3. 类级 & 方法级 (Class & Method Level) =================
class TestUserLogin:
# 针对整个类,在类的第一个用例前和最后一个用例后运行一次
def setup_class(self):
print("\n 【类级】setup_class:TestUserLogin 类开始执行。(例如:启动浏览器/创建测试用户)")
def teardown_class(self):
print("\n 【类级】teardown_class:TestUserLogin 类执行完毕。(例如:关闭浏览器/删除测试用户)")
# 针对类里面的每一个测试方法,在每个方法前后都会运行
def setup_method(self):
print("\n [方法级] setup_method:准备执行类中的测试方法。(例如:打开登录页面)")
def teardown_method(self):
print(" [方法级] teardown_method:类中的测试方法执行完毕。(例如:清除浏览器 Cookie)")
def test_login_success(self):
print(" -> 正在执行测试方法: test_login_success")
assert "login" in "login_success"
def test_login_fail(self):
print(" -> 正在执行测试方法: test_login_fail")
assert 3 > 2
7. 测试用例执行顺序
-
默认顺序:pytest 默认按照代码在文件中从上到下的顺序执行。
-
自定义顺序 :可以通过安装
pytest-ordering插件,并使用装饰器来改变顺序:pythonimport pytest @pytest.mark.run(order=2) def test_two(): pass @pytest.mark.run(order=1) def test_one(): pass
8. skip 和 skipif:测试用例跳过
有时某些用例还没写完,或者在特定环境下不需要运行,可以跳过它们。
python
import pytest
import sys
# 无条件跳过
@pytest.mark.skip(reason="接口还在开发中,暂不执行")
def test_unfinished_api():
pass
# 有条件跳过 (例如:如果不是 Windows 系统则跳过)
@pytest.mark.skipif(sys.platform != "win32", reason="仅在 Windows 下运行")
def test_windows_feature():
pass
9. 解决接口参数依赖 (结合 pytest + requests 练习)
在编写 requests 接口自动化测试时,经常遇到接口依赖 的问题。比如:"获取用户信息"接口,依赖"登录"接口返回的 Token。
在 pytest 中,解决这类数据传递的最佳实践是使用 Fixture (夹具),它比传统的 setup 更灵活。
python
import pytest
import requests
# 1. 定义一个 fixture,用于模拟登录获取 Token
@pytest.fixture()
def get_token():
# 实际场景下这里会是一个 requests.post() 登录请求
# response = requests.post("http://api.example.com/login", json={"user": "admin", "pwd": "123"})
# token = response.json().get("token")
print("\n--- 正在调用登录接口提取 Token ---")
token = "eyJhbGciOiJIUzI1NiIsInR5cCI..." # 模拟提取到的 Token
return token
# 2. 在需要依赖的测试用例中,直接将 fixture 的名字作为参数传入
def test_get_user_info(get_token):
# get_token 变量现在包含了上面 fixture 返回的值
headers = {"Authorization": f"Bearer {get_token}"}
# 携带 token 发起下一个请求
# response = requests.get("http://api.example.com/user_info", headers=headers)
# assert response.status_code == 200
print(f"\n使用 Token 请求用户信息: {headers}")
assert get_token is not None