目录
1. 为什么选择 Pytest?
Pytest 的主要特性:
2. 安装 Pytest
3. Pytest 项目结构设计
目录结构说明:
4. pytest的命名规则
5. 使用 Fixture 进行测试数据初始化
示例:使用 Fixture 初始化测试数据
fixture 执行顺序
6. Pytest 运行方式
6.1 在命令行中运行测试
常用运行命令
6.2 通过 PyCharm 运行测试
6.3 通过配置文件运行测试
7. 编写第一个接口测试用例
7.1 示例接口测试用例
7.2 编写 GET 请求的测试用例
7.3 运行测试
7.4测试失败时的情况
8. 测试多个请求方法
8.1 POST 请求测试用例
代码解释
9. 封装 HTTP 请求方法
9.1 编写封装的请求工具类
9.2 重写测试用例
10. 使用配置文件管理 API 地址
10.1 创建配置文件
10.2 读取配置文件
10.3 在测试用例中使用配置文件
11. 总结
Pytest 是 Python 中非常流行的测试框架,因其简洁的语法、灵活的扩展能力以及丰富的插件生态广受开发者和测试工程师的欢迎。它支持编写和执行单元测试、集成测试等各种测试类型。通过与 Requests 库结合,Pytest 可以非常方便地实现接口自动化测试。相比其他测试框架,Pytest 更加轻量化,并且无需继承类或编写过多的 boilerplate 代码,非常适合接口测试。
assert
语句进行断言,语法简洁明了,让测试结果更易读、易调试。在开始使用 Pytest 之前,首先需要安装它。你可以通过 pip 命令安装:
pip install pytest
安装完成后,你可以使用以下命令检查安装是否成功:
pytest --version
如果输出 Pytest 的版本信息,说明安装成功。
为了构建一个可扩展的接口自动化测试框架,我们需要规划项目结构,确保代码的可维护性和易扩展性。通常的项目目录结构如下:
project_root/
│
├── tests/ # 测试用例目录
│ ├── test_api.py # 接口测试用例文件
│
├── config/ # 配置文件目录
│ └── config.yaml # 配置文件(如API地址等)
│
├── utils/ # 工具类目录
│ └── request_helper.py # 封装请求的方法
│
└── pytest.ini # Pytest 配置文件
1)模块名(py文件)必须是以test_开头或者_test结尾
2)测试类(class)必须以Test开头,并且不能带init方法,类里的方法必须以test_开头
3)测试用例(函数)必须以test_开头
以下是一个简单的测试用例示例,文件名为 test_sample.py
:
Class TestSample:
def test_addition():
assert 1 + 1 == 2
def test_subtraction():
assert 2 - 1 == 1
Pytest 提供了 fixture 功能,用于在测试运行前设置测试环境,或在测试运行后清理资源。Fixture 可以用于准备测试数据、建立数据库连接等。
import pytest
# 定义 fixture
@pytest.fixture
def sample_data():
return {"name": "pytest", "age": 5}
# 测试用例中使用 fixture
def test_check_sample_data(sample_data):
assert sample_data["name"] == "pytest"
assert sample_data["age"] == 5
在上面的例子中,sample_data
是一个 fixture,返回一个字典对象,并被测试函数 test_check_sample_data()
使用。每次运行测试时,Pytest 会自动调用该 fixture。
Fixture 可以指定执行的顺序,默认是每个测试用例前都会重新调用一次 fixture。如果你希望某个 fixture 在所有测试用例执行前只执行一次,可以使用 scope="module"
参数:
@pytest.fixture(scope="module")
def setup():
print("Setup for the module")
Pytest 提供了多种运行方式来执行测试用例,可以通过命令行、PyCharm 的 UI 界面或配置文件来运行测试。
最常用的方式是在终端中直接运行 Pytest 命令:
运行测试,在终端中进入包含测试文件的目录,并执行以下命令:
pytest
Pytest 会自动扫描当前目录及其子目录中的测试文件,找到所有符合命名规则的测试用例并执行。
如果想运行某个特定的测试文件,可以指定文件路径:
pytest tests/test_sample.py
-v 输出调试信息。如:打印信息 pytest -v tests/test_sample.py
-q 输出简单信息。 pyets -q tests/test_sample.py
-s 输出更详细的信息,如:文件名、用例名 pytest -s tests/test_sample.py
-n 多线程或分布式运行测试用例 pytest -n 4(会使用 4 个线程并行执行测试用例)
-x 只要有一个用例执行失败,就停止执行测试 pytest -x tests/test_sample.py
– maxfail 出现N个测试用例失败,就停止测试 pytest --maxfail=2 tests/test_sample.py
–html=report.html 生成测试报告 pytest tests/test_sample.py --html=./report/report.html
-m 运行带标记的测试用例 pytest -m smoke(使用@pytest.mark.smoke装饰器进行打标记)
-k 根据测试用例的部分字符串指定测试用例,可以使用and,or pytest -k “MyClass and not method”,这条命令会匹配文件名、类名、方法名匹配表达式的用例,这里这条命令会运行 TestMyClass.test_something, 不会执行 TestMyClass.test_method_simple
PyCharm 集成了对 Pytest 的支持,可以方便地在 IDE 中运行测试。
配置 Pytest 为默认测试框架:
运行测试用例:
你可以使用 Pytest 的配置文件 pytest.ini
来定制测试运行的行为。创建 pytest.ini
文件并配置一些选项:
[pytest]
addopts=-vs -m slow --maxfail=2 -q --html=./report/report.html
testpaths=testcase
test_files=test_*.py
test_classes=Test*
test_functions=test_*
makerers=第一次执行
代码解释
pytset.ini文件尽可能不要出现中文。
在使用配置文件后,你只需运行 pytest
,Pytest 会按照配置文件中的规则运行测试。
接下来,我们将编写一个简单的接口测试用例,使用 Requests 库发送 HTTP 请求,并使用 Pytest 进行测试。
我们将测试一个公开的 API:https://jsonplaceholder.typicode.com/posts
,它提供了一个模拟的 RESTful API,用于测试和演示。
首先,我们编写一个 GET 请求的测试用例,验证返回的数据和状态码是否正确。
创建一个名为tests/test_api.py文件
,并编写如下代码:
import requests
def test_get_post():
url = "https://jsonplaceholder.typicode.com/posts/1"
response = requests.get(url)
# 验证状态码是否为 200
assert response.status_code == 200, f"Expected 200, but got {response.status_code}"
# 验证返回的数据是否符合预期
data = response.json()
assert data["userId"] == 1, f"Expected userId to be 1, but got {data['userId']}"
assert data["id"] == 1, f"Expected id to be 1, but got {data['id']}"
代码解释
test_get_post()
: Pytest 自动识别以 test_
开头的函数为测试用例。requests.get(url)
: 发送 GET 请求并获取响应。assert response.status_code == 200
: 验证响应的状态码是否为 200,表示请求成功。assert data["userId"] == 1
: 验证响应的 JSON 数据中 userId
字段是否为 1。运行测试,在终端中进入包含测试文件的目录,并执行以下命令:
pytest
Pytest 会自动发现 tests
目录下的以 test_
开头测试文件并执行。若测试通过,输出类似如下:
============================= test session starts ==============================
collected 1 item
test_api.py . [100%]
============================== 1 passed in 0.12s ===============================
这表示测试用例成功通过,.
号表示测试通过。
如果测试失败,Pytest 将显示详细的错误信息,帮助你快速定位问题。例如,如果我们将 userId
的预期值改为 2,重新运行测试,输出将类似于:
=================================== FAILURES ===================================
_______________________________ test_get_post _________________________________
def test_get_post():
url = "https://jsonplaceholder.typicode.com/posts/1"
response = requests.get(url)
assert response.status_code == 200, f"Expected 200, got {response.status_code}"
data = response.json()
> assert data["userId"] == 2, f"Expected userId to be 2, got {data['userId']}"
E AssertionError: Expected userId to be 2, got 1
test_api.py:10: AssertionError
=========================== short test summary info ============================
FAILED test_api.py::test_get_post - AssertionError: Expected userId to be 2, got 1
============================== 1 failed in 0.15s ===============================
从输出信息可以清楚看到,断言失败的原因是 userId
的预期值和实际值不符。
Pytest 还可以帮助我们测试其他 HTTP 请求方法,例如 POST、PUT、DELETE 等。下面我们来编写一个简单的 POST 请求测试用例。
以下是一个发送 POST 请求并验证响应的示例:
import requests
# 测试 POST 请求
def test_post_request():
url = "https://jsonplaceholder.typicode.com/posts"
data = {
"title": "foo",
"body": "bar",
"userId": 1
}
response = requests.post(url, json=data)
# 验证状态码
assert response.status_code == 201, f"Expected 201, got {response.status_code}"
# 验证返回数据的 title
response_data = response.json()
assert response_data["title"] == "foo", f"Expected title to be 'foo', got {response_data['title']}"
requests.post(url, json=data)
: 发送 POST 请求,向服务器提交数据。assert response.status_code == 201
: 验证状态码为 201,表示资源创建成功。assert response_data["title"] == "foo"
: 验证服务器返回的响应数据中的 title
是否为预期值 foo
。为了提高代码的可维护性,我们可以将 HTTP 请求操作封装成工具类方法。这样在多个测试用例中复用同样的请求逻辑时,可以减少重复代码。
在 utils/request_helper.py
中编写一个封装的请求方法:
import requests
class RequestHelper:
@staticmethod
def get(url, params=None, headers=None):
try:
response = requests.get(url, params=params, headers=headers)
return response
except requests.RequestException as e:
print(f"HTTP请求出错: {e}")
return None
更新 tests/test_api.py
文件:
from utils.request_helper import RequestHelper
def test_get_post():
url = "https://jsonplaceholder.typicode.com/posts/1"
response = RequestHelper.get(url)
assert response.status_code == 200
data = response.json()
assert data["userId"] == 1
assert data["id"] == 1
在 config/
目录下创建一个名为 config.yaml
的文件:
base_url: "https://jsonplaceholder.typicode.com"
编写工具函数来加载配置:
import yaml
def load_config():
with open("config/config.yaml", 'r') as file:
return yaml.safe_load(file)
更新 tests/test_api.py
文件:
from utils.request_helper import RequestHelper
from utils.config_loader import load_config
def test_get_post():
config = load_config()
url = f"{config['base_url']}/posts/1"
response = RequestHelper.get(url)
assert response.status_code == 200
data = response.json()
assert data["userId"] == 1
assert data["id"] == 1
通过本篇文章,我们了解了如何使用 Pytest 进行接口自动化测试,掌握了 Pytest 的多种启动方式,封装了 HTTP 请求方法,并学会了如何使用配置文件管理 API 地址。从基础的 GET、POST 请求测试到参数化测试,Pytest 提供了强大的测试功能,同时保持了简单易用的特性。在实际的接口测试项目中,Pytest 是一个非常适合的选择,尤其是在处理大量接口测试用例时。在后续文章中,我们将继续探讨 Pytest 的进阶用法。