好嘞,各位观众老爷,今天咱们就来聊聊 API 自动化测试这档子事儿!😎 保证让大家听得懂,学得会,还能笑出腹肌!
API 自动化测试:Requests 库与 Pytest 实践
各位,API 自动化测试,听起来高大上,实际上就是用代码代替人工,自动地去验证 API 接口是否符合预期。这就像咱们的“智能管家”,24小时不间断地帮你检查家里的电器是否正常工作,省时省力,简直不要太爽!
为什么要搞 API 自动化测试?
想象一下,如果没有自动化测试,每次代码更新后,都需要测试人员手动去调用每个 API,验证返回结果是否正确。这就像在古代,每次打仗都要靠人力去探路,效率低下,还容易出错。
有了 API 自动化测试,我们可以:
- 提高测试效率: 代码跑起来,比人手快多了,省下来的时间可以摸鱼…咳咳,可以做更有意义的事情!
- 减少人工错误: 人总是会疲劳的,代码可不会,只要你写对了,它就能一直稳定地执行。
- 尽早发现问题: 在开发阶段就能发现 API 的问题,避免问题蔓延到生产环境,减少损失。
- 保证产品质量: 自动化测试可以覆盖更多的测试场景,提高测试的覆盖率,保证产品的质量。
今天的主角:Requests 和 Pytest
工欲善其事,必先利其器。咱们今天的主角就是 Requests 和 Pytest。
-
Requests: Python 中发起 HTTP 请求的利器,用它来调用 API 就像用筷子吃饭一样简单!它能模拟各种 HTTP 请求,比如 GET、POST、PUT、DELETE 等等,还能处理各种复杂的请求头和请求体。
-
Pytest: Python 中强大的测试框架,用它来组织和执行测试用例,就像用文件夹整理文件一样清晰!它支持各种断言方式,可以方便地验证 API 的返回结果是否符合预期。
Requests:HTTP 请求的艺术家
Requests 库就像一位 HTTP 请求的艺术家,可以创作出各种各样的 HTTP 请求作品。咱们先来认识一下这位艺术家。
-
安装 Requests:
pip install requests
这就像给艺术家配备画笔和颜料,没有这些工具,他就无法创作。
-
发送 GET 请求:
import requests url = "https://api.github.com/users/octocat" response = requests.get(url) print(response.status_code) # 打印状态码 print(response.json()) # 打印 JSON 格式的响应内容
这段代码就像艺术家画了一幅简单的素描,请求 GitHub API 获取 octocat 用户的信息。
response.status_code
返回的是 HTTP 状态码,比如 200 表示请求成功,404 表示资源未找到。response.json()
返回的是 JSON 格式的响应内容,可以直接转换成 Python 字典。 -
发送 POST 请求:
import requests import json url = "https://httpbin.org/post" # 一个用于测试 HTTP 请求的网站 headers = {'Content-Type': 'application/json'} data = {'key': 'value'} response = requests.post(url, headers=headers, data=json.dumps(data)) print(response.status_code) print(response.json())
这段代码就像艺术家创作了一幅油画,发送一个 POST 请求到 httpbin.org,并携带 JSON 格式的数据。
headers
参数用于设置请求头,data
参数用于设置请求体。注意,POST 请求的请求体通常是 JSON 格式的,需要使用json.dumps()
函数将 Python 字典转换成 JSON 字符串。 -
其他请求类型:
Requests 还支持 PUT、DELETE、PATCH 等其他 HTTP 请求类型,用法类似,可以根据需要选择合适的请求类型。
response = requests.put(url, data=data) response = requests.delete(url) response = requests.patch(url, data=data)
-
Requests常用方法总结:
方法名 | 描述 | 常见应用场景 |
---|---|---|
get() |
发送 GET 请求,用于获取资源。 | 获取用户信息、查询商品列表、获取新闻资讯等。 |
post() |
发送 POST 请求,用于创建新资源或者提交数据。 | 用户注册、提交评论、创建订单等。 |
put() |
发送 PUT 请求,用于更新已有资源。 | 更新用户信息、修改商品信息等。 |
delete() |
发送 DELETE 请求,用于删除资源。 | 删除用户信息、删除商品信息等。 |
head() |
发送 HEAD 请求,类似于 GET 请求,但不返回响应体,只返回响应头。 | 检查资源是否存在、获取资源的大小等。 |
options() |
发送 OPTIONS 请求,用于获取服务器支持的 HTTP 方法。 | 了解服务器支持的请求类型,常用于跨域请求的预检。 |
patch() |
发送 PATCH 请求,用于部分更新资源。 | 类似 PUT,但只需要更新资源的部分字段。 |
Pytest:测试用例的指挥家
Pytest 就像一位测试用例的指挥家,可以组织和执行各种测试用例,并生成详细的测试报告。咱们也来认识一下这位指挥家。
-
安装 Pytest:
pip install pytest
这就像给指挥家配备指挥棒和乐谱,没有这些工具,他就无法指挥乐队。
-
编写测试用例:
import pytest import requests def test_get_user(): url = "https://api.github.com/users/octocat" response = requests.get(url) assert response.status_code == 200 assert response.json()['login'] == 'octocat' def test_post_request(): url = "https://httpbin.org/post" headers = {'Content-Type': 'application/json'} data = {'key': 'value'} response = requests.post(url, headers=headers, json=data) assert response.status_code == 200 assert response.json()['json']['key'] == 'value'
这段代码就像指挥家编写了两首乐曲,分别测试了 GET 和 POST 请求。Pytest 会自动识别以
test_
开头的函数作为测试用例。assert
语句用于断言,如果断言失败,Pytest 会标记该测试用例为失败。 -
运行测试用例:
pytest
这就像指挥家开始指挥乐队演奏乐曲,Pytest 会自动查找并执行所有的测试用例,并输出测试结果。
-
Pytest常用参数:
参数/选项 | 描述 | 示例 |
---|---|---|
-v |
verbose (详细) 模式,显示更详细的测试执行信息。 | pytest -v |
-s |
允许捕获标准输出 (stdout) 和标准错误 (stderr),通常用于在测试中打印调试信息。 | pytest -s |
-k |
通过关键字表达式匹配测试用例的名称,只运行匹配的测试用例。 | pytest -k "test_login" (运行包含 "test_login" 的测试用例) |
-x |
遇到第一个失败的测试用例时停止运行。 | pytest -x |
--maxfail=N |
允许的最大失败数量,达到这个数量后停止运行。 | pytest --maxfail=2 (允许最多 2 个测试用例失败) |
-m |
运行带有特定标记 (marker) 的测试用例。标记用于对测试用例进行分类和分组。 | pytest -m "smoke" (运行所有标记为 "smoke" 的测试用例) |
--pdb |
当测试用例失败时,自动进入 Python 调试器 (pdb)。 | pytest --pdb |
--lf |
只运行上次运行失败的测试用例 (last failed)。 | pytest --lf |
--ff |
先运行上次运行失败的测试用例,然后运行其他测试用例 (failed first)。 | pytest --ff |
--collect-only |
只收集测试用例,不执行它们。 | pytest --collect-only |
--durations=N |
显示运行时间最长的 N 个测试用例。 | pytest --durations=10 (显示运行时间最长的 10 个测试用例) |
--html=path |
生成 HTML 格式的测试报告,path 是报告的保存路径。需要安装 pytest-html 插件。 |
pytest --html=report.html |
--junit-xml=path |
生成 JUnit XML 格式的测试报告,path 是报告的保存路径。这种格式常用于持续集成系统。 |
pytest --junit-xml=report.xml |
setup() /teardown() |
在每个测试用例之前/之后运行的 setup 和 teardown 函数,用于准备和清理测试环境。 | 在测试类或测试函数中使用 setup() 和 teardown() 函数。 |
fixture |
允许创建可重用的测试资源和依赖项,例如数据库连接、测试数据等。可以通过装饰器 @pytest.fixture 定义 fixture。 |
@pytest.fixture def db_connection(): ... |
parametrize |
允许使用不同的参数多次运行同一个测试用例。可以通过装饰器 @pytest.mark.parametrize 定义参数。 |
@pytest.mark.parametrize("input, expected", [(1, 2), (3, 4)]) |
API 自动化测试实战:用户管理系统
光说不练假把式,咱们来一个实战案例,用 Requests 和 Pytest 测试一个简单的用户管理系统 API。
-
API 接口:
GET /users
:获取所有用户列表。POST /users
:创建新用户。GET /users/{id}
:获取指定 ID 的用户信息。PUT /users/{id}
:更新指定 ID 的用户信息。DELETE /users/{id}
:删除指定 ID 的用户。
-
测试用例:
import pytest import requests import json BASE_URL = "http://localhost:8000" # 假设 API 运行在本地 8000 端口 def test_get_users(): response = requests.get(f"{BASE_URL}/users") assert response.status_code == 200 assert isinstance(response.json(), list) def test_create_user(): data = {"name": "Test User", "email": "[email protected]"} headers = {'Content-Type': 'application/json'} response = requests.post(f"{BASE_URL}/users", headers=headers, data=json.dumps(data)) assert response.status_code == 201 assert response.json()['name'] == "Test User" # 获取新创建的用户 ID,用于后续测试 global user_id user_id = response.json()['id'] def test_get_user_by_id(): response = requests.get(f"{BASE_URL}/users/{user_id}") assert response.status_code == 200 assert response.json()['name'] == "Test User" def test_update_user(): data = {"name": "Updated User", "email": "[email protected]"} headers = {'Content-Type': 'application/json'} response = requests.put(f"{BASE_URL}/users/{user_id}", headers=headers, data=json.dumps(data)) assert response.status_code == 200 assert response.json()['name'] == "Updated User" def test_delete_user(): response = requests.delete(f"{BASE_URL}/users/{user_id}") assert response.status_code == 204 # 验证用户是否已删除 response = requests.get(f"{BASE_URL}/users/{user_id}") assert response.status_code == 404
这段代码就像一位厨师烹饪了一桌丰盛的菜肴,每一道菜都对应一个 API 接口的测试。
test_get_users()
测试获取所有用户列表的接口,验证状态码是否为 200,以及返回结果是否为列表。test_create_user()
测试创建新用户的接口,验证状态码是否为 201,以及返回结果中包含新用户的姓名。test_get_user_by_id()
测试获取指定 ID 的用户信息接口,验证状态码是否为 200,以及返回结果中包含用户的姓名。test_update_user()
测试更新指定 ID 的用户信息接口,验证状态码是否为 200,以及返回结果中包含更新后的用户姓名。test_delete_user()
测试删除指定 ID 的用户接口,验证状态码是否为 204,以及用户是否已成功删除。
-
运行测试用例:
pytest
运行测试用例后,Pytest 会输出测试结果,告诉你哪些测试用例通过了,哪些测试用例失败了。
进阶技巧:参数化测试、Fixture、Mock
-
参数化测试:
如果我们需要用不同的参数多次运行同一个测试用例,可以使用 Pytest 的参数化功能。
import pytest @pytest.mark.parametrize("input, expected", [(1, 2), (3, 4), (5, 6)]) def test_add(input, expected): assert input + 1 == expected
这段代码就像一位老师给学生布置了三道不同的加法题,每道题都用不同的参数运行
test_add()
函数。 -
Fixture:
Fixture 可以用于创建可重用的测试资源和依赖项,比如数据库连接、测试数据等。
import pytest import requests @pytest.fixture def api_client(): base_url = "http://localhost:8000" session = requests.Session() session.headers.update({"Content-Type": "application/json"}) yield session session.close() def test_get_users(api_client): response = api_client.get("/users") assert response.status_code == 200
这段代码就像一位管家提前准备好了茶水和点心,供客人享用。
api_client
fixture 创建了一个 Requests Session 对象,并设置了默认的请求头,供测试用例使用。 -
Mock
Mock 是测试中一种常用的技术,用于模拟(mock)系统中某些组件或服务的行为。这在以下情况下特别有用:- 隔离测试目标:当你的测试目标依赖于其他组件或服务时,使用 mock 可以隔离测试目标,确保测试只关注目标自身的行为,而不是依赖项的行为。
- 模拟复杂或不可预测的行为:某些组件或服务的行为可能难以预测或控制,例如网络请求、数据库查询等。使用 mock 可以模拟这些行为,使测试更加可控和可靠。
- 加速测试:某些组件或服务的执行速度可能较慢,例如数据库查询。使用 mock 可以模拟这些行为,加速测试的执行速度。
- 模拟错误情况:使用 mock 可以模拟各种错误情况,例如网络连接失败、数据库查询失败等,以便测试目标在这些情况下的行为。
import pytest import requests from unittest.mock import patch def get_user_name(user_id): response = requests.get(f"https://api.example.com/users/{user_id}") response.raise_for_status() # 如果请求失败,抛出异常 return response.json()["name"] @patch("requests.get") def test_get_user_name(mock_get): # 配置 mock 对象,使其返回一个模拟的响应 mock_response = Mock() mock_response.json.return_value = {"name": "Mock User"} mock_get.return_value = mock_response # 调用被测试函数 user_name = get_user_name(123) # 断言 mock 对象是否被调用,以及调用时的参数是否正确 mock_get.assert_called_once_with("https://api.example.com/users/123") # 断言被测试函数的返回值是否正确 assert user_name == "Mock User"
总结
API 自动化测试是保证产品质量的重要手段。Requests 和 Pytest 是 Python 中进行 API 自动化测试的利器。掌握了这两个工具,你就可以轻松地编写出高质量的 API 自动化测试用例,为你的产品保驾护航!💪
希望今天的分享对大家有所帮助!如果大家还有什么疑问,欢迎在评论区留言,咱们一起讨论!🎉