API 自动化测试:Requests 库与 Pytest 实践

好嘞,各位观众老爷,今天咱们就来聊聊 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 请求作品。咱们先来认识一下这位艺术家。

  1. 安装 Requests:

    pip install requests

    这就像给艺术家配备画笔和颜料,没有这些工具,他就无法创作。

  2. 发送 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 字典。

  3. 发送 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 字符串。

  4. 其他请求类型:

    Requests 还支持 PUT、DELETE、PATCH 等其他 HTTP 请求类型,用法类似,可以根据需要选择合适的请求类型。

    response = requests.put(url, data=data)
    response = requests.delete(url)
    response = requests.patch(url, data=data)
  5. Requests常用方法总结:

方法名 描述 常见应用场景
get() 发送 GET 请求,用于获取资源。 获取用户信息、查询商品列表、获取新闻资讯等。
post() 发送 POST 请求,用于创建新资源或者提交数据。 用户注册、提交评论、创建订单等。
put() 发送 PUT 请求,用于更新已有资源。 更新用户信息、修改商品信息等。
delete() 发送 DELETE 请求,用于删除资源。 删除用户信息、删除商品信息等。
head() 发送 HEAD 请求,类似于 GET 请求,但不返回响应体,只返回响应头。 检查资源是否存在、获取资源的大小等。
options() 发送 OPTIONS 请求,用于获取服务器支持的 HTTP 方法。 了解服务器支持的请求类型,常用于跨域请求的预检。
patch() 发送 PATCH 请求,用于部分更新资源。 类似 PUT,但只需要更新资源的部分字段。

Pytest:测试用例的指挥家

Pytest 就像一位测试用例的指挥家,可以组织和执行各种测试用例,并生成详细的测试报告。咱们也来认识一下这位指挥家。

  1. 安装 Pytest:

    pip install pytest

    这就像给指挥家配备指挥棒和乐谱,没有这些工具,他就无法指挥乐队。

  2. 编写测试用例:

    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 会标记该测试用例为失败。

  3. 运行测试用例:

    pytest

    这就像指挥家开始指挥乐队演奏乐曲,Pytest 会自动查找并执行所有的测试用例,并输出测试结果。

  4. 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。

  1. API 接口:

    • GET /users:获取所有用户列表。
    • POST /users:创建新用户。
    • GET /users/{id}:获取指定 ID 的用户信息。
    • PUT /users/{id}:更新指定 ID 的用户信息。
    • DELETE /users/{id}:删除指定 ID 的用户。
  2. 测试用例:

    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,以及用户是否已成功删除。
  3. 运行测试用例:

    pytest

    运行测试用例后,Pytest 会输出测试结果,告诉你哪些测试用例通过了,哪些测试用例失败了。

进阶技巧:参数化测试、Fixture、Mock

  1. 参数化测试:

    如果我们需要用不同的参数多次运行同一个测试用例,可以使用 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() 函数。

  2. 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 对象,并设置了默认的请求头,供测试用例使用。

  3. 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 自动化测试用例,为你的产品保驾护航!💪

希望今天的分享对大家有所帮助!如果大家还有什么疑问,欢迎在评论区留言,咱们一起讨论!🎉

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注