5.接口自动化测试(4)

文章目录

  • 2.接口自动化测试
    • [2.5 pytest](#2.5 pytest)
      • [2.5.6 断言](#2.5.6 断言)
      • [2.5.7 参数化](#2.5.7 参数化)
      • [2.5.8 fixture](#2.5.8 fixture)
        • [2.5.8.1 基本使用](#2.5.8.1 基本使用)
        • [2.5.8.2 fixture嵌套](#2.5.8.2 fixture嵌套)
        • [2.5.8.3 请求多个fixture](#2.5.8.3 请求多个fixture)
        • [2.5.8.4 yield fixture](#2.5.8.4 yield fixture)

2.接口自动化测试

2.5 pytest

2.5.6 断言

断言( assert )是一种调试辅助工具,用于检查程序的状态是否符合预期。如果断言失败(即条件为假),Python解释器将抛出一个 AssertionError 异常。断言通常用于检测程序中的逻辑错误。

pytest 允许你在 Python 测试中使用标准的 Python assert 语句来验证预期和值。
基本语法:

assert 条件, 错误信息

  • 条件 :必须是一个布尔表达式。
  • 错误信息 :当条件为假时显示的错误信息,可选。

免费学习API资源:http://jsonplaceholder.typicode.com/

示例1:基本数据类型的断言

python 复制代码
#断言整数
a = 1
b = 2
assert a == b
#断言字符串
str = "hello"
assert "hello" == str

示例2:数据结构断言

python 复制代码
def test():
    # 断言列表
    expect_list = [1, 'apple', 3.14]
    actual_list = [1, 'apple', 3.14]
    # 断言元组
    expect_tuple = (1, 'apple', 3.14)
    actual_tuple = (1, 'apple', 3.14)

    # 断言字典
    expect_dict = {'name': 'Alice', 'age': 25}
    actual_dict = {'name': 'Alice', 'age': 25}
    # 断言集合
    expect_set = {1, 2, 3, 'apple'}
    actual_set = {1, 2, 3, 'apple'}
    assert expect_list == actual_list
    assert expect_tuple == actual_tuple
    assert expect_dict == actual_dict
    assert expect_set == actual_set

运行:

示例3:函数断言

python 复制代码
def divide(a, b):
    assert b != 0, "除数不能为0"
    return a / b
# 正常情况
print(divide(10, 2)) # 输出 5.0
# 触发断言
print(divide(10, 0)) # 抛出 AssertionError: 除数不能为0

打印:

示例4:接口返回值断言

python 复制代码
import requests
# 断言接口返回值完整字段和值
def test1():
    url = "http://jsonplaceholder.typicode.com/posts/1"
    r = requests.get(url=url)
    expect_data = {
        "userId": 1,
        "id": 1,
        "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
        "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
    }
    print(r.json())
    assert r.json() == expect_data
    assert r.json()['userId'] == 1


# 断言接口返回值重要字段
def test2():
    url = "http://jsonplaceholder.typicode.com/comments?postId=1"
    r = requests.get(url=url)
    print(r.json())
    assert r.json()[0]['id'] == 1


# 断言接口html返回值
def test3():
    url = "http://jsonplaceholder.typicode.com/"
    r = requests.get(url=url)
    assert "Use your own data" in r.text

运行:


2.5.7 参数化

参数化设计是自动化设计中的一个重要组成部分,它通过定义设计参数和规则,使得设计过程更加灵活和可控。

pytest中内置的 pytest.mark.parametrize 装饰器允许对测试函数的参数进行参数化。

示例1:在用例上使用参数化

python 复制代码
import pytest
@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6),
                                                     ("6*9", 42)])
def test_eval(test_input, expected):
    assert eval(test_input) == expected

打印:

这里, @parametrize 装饰器定义了三个不同的 (test_input,expected) 元组,以便test_eval 函数将依次使用它们运行三次。


也可以在类或模块上使用 parametrize 标记,这将使用参数集调用多个函数

示例2:在类上使用参数化

python 复制代码
import pytest
@pytest.mark.parametrize("n,expected", [(1, 2), (3, 4)])
class TestClass:
    def test_simple_case(self, n, expected):
        assert n + 1 == expected
    def test_weird_simple_case(self, n, expected):
        assert (n * 1) + 1 == expected

打印:

如果要对模块中的所有测试进行参数化,可以将 pytestmark 全局变量赋值:

python 复制代码
import pytest
pytestmark = pytest.mark.parametrize("n,expected", [(1, 2), (3, 4)])
class TestClass:
    def test_simple_case(self, n, expected):
        assert n + 1 == expected
    def test_weird_simple_case(self, n, expected):
        assert (n * 1) + 1 == expected

打印:


除了使用 @parametrize 添加参数化外, pytest.fixture() 允许对 fixture 函数进行参数化。

示例3:自定义参数化数据源

python 复制代码
def data_provider(): # 一个普通的Python函数,返回一个列表 ["a", "b"]作为测试数据的数据源
    return ["a", "b"]

# 定义一个测试函数,它依赖于上面函数的返回值
@pytest.mark.parametrize("data", data_provider())
'''
这是pytest的参数化装饰器
"data":参数名(测试函数的参数)
data_provider():数据源(返回列表 ["a", "b"])
'''

def test_data(data):
    assert data != None
    print(f"Testing with data provider: {data}")
'''
接受一个参数 data
执行断言 assert data != None
打印测试信息
'''

运行:


2.5.8 fixture

pytest 中的 fixture 是一种强大的机制,用于提供测试函数所需的资源或上下文。它可以用于设置测试环境、准备数据等。

以下是 fixture 的一些核心概念和使用场景

2.5.8.1 基本使用

示例1:使用与不使用fixture标记

python 复制代码
def fixture_01():
    print("第一个fixture标记的方法")
def test_01():
    fixture_01()
    print("第一个测试用例")

打印:

fixture标记的方法调用

python 复制代码
import pytest
@pytest.fixture
def fixture_01():
    print("第一个fixture标记的方法")
def test_01(fixture_01):
    print("第一个测试用例")

打印:

虽然看起来结果一模一样,但是执行机制完全不同

代码1的执行流程:

  1. 调用 test_01()
  2. test_01() 内部调用 fixture_01()
  3. 执行 fixture_01() 的print
  4. 返回继续执行 test_01() 的print

代码2的执行流程:

  1. pytest发现 test_01 需要 fixture_01
  2. pytest执行 fixture_01(作为setup)
  3. 执行 fixture_01 的print
  4. 执行 test_01 的print
    前者需要在方法体中调用,而后者可以将函数名作为参数进行调用。

测试脚本中存在的很多重复的代码、公共的数据对象时,使用 fixture 最为合适


示例2:访问列表页和详情页之前都需要执行登录操作

python 复制代码
import pytest
@pytest.fixture
def login():
    print("---执行登陆操作-----")
def test_list(login):
    print("---访问列表页")
def test_detail(login):
    print("---访问详情页")

打印:

通过使用 @pytest.fixture 装饰器来告诉 pytest 一个特定函数是一个 fixture,通过运行结果可见,在执行列表页和详情页之前都会先执行 login 方法。


2.5.8.2 fixture嵌套

代码:

python 复制代码
import pytest
# 安排
@pytest.fixture
def first_entry():
    return "a"
# 安排
@pytest.fixture
def order(first_entry):
    return [first_entry]
def test_string(order):
    # 行动
    order.append("b")
    # 断言
    assert order == ["a", "b"]

打印:

测试不必局限于单个 fixture ,它们可以依赖于自己想要的任意数量的 fixture ,并且 fixture 也可以使用其他 fixture

pytest 最伟大的优势之一是其极其灵活的 fixture 系统,它允许我们将测试的复杂需求简化为更简单和有组织的函数,我们只需要每个函数描述它们所依赖的事物。


2.5.8.3 请求多个fixture

测试和 fixture 不仅限于一次请求单个 fixture ,它们可以请求任意多个。

python 复制代码
import pytest
class Fruit:
   def __init__(self, name):
        self.name = name
   def __eq__(self, other):
      return self.name == other.name

@pytest.fixture
def my_fruit():
    return Fruit("apple")
@pytest.fixture
def fruit_basket(my_fruit):
    return [Fruit("banana"), my_fruit]
def test_my_fruit_in_basket(my_fruit, fruit_basket):
    assert my_fruit in fruit_basket

打印:


2.5.8.4 yield fixture

当我们运行测试时,我们希望确保它们能够自我清理,以便它们不会干扰其他测试(同时也避免留下大量测试数据来膨胀系统)。pytest中的 fixture 提供了一个非常有用拆卸系统,它允许我们为每个 fixture 定义具体的清理步骤。
"Yield" fixture 使用 yield 而不是 return 。有了这些 fixture ,我们可以运行一些代码,并将对象返回给请求的 fixture/test ,就像其他 fixture 一样。唯一的不同是:

  • return 被替换为 yield
  • fixture 的任何拆卸代码放置在 yield 之后。
    一旦 pytest 确定了 fixture 的线性顺序,它将运行每个 fixture 直到它返回或 yield ,然后继续执行列表中的下一个 fixture 做同样的事情。

测试完成后, pytest 将逆向遍历 fixture 列表,对于每个 yieldfixture ,运行 yield语句之后的代码。

示例1:

python 复制代码
import pytest
@pytest.fixture
def open_close():
    print("前置操作,初始化.....")
    yield
    print("后置操作,清理数据.....")
def test_01(open_close):
    print("第一个测试用例")

打印:

示例2:创建文件句柄与关闭文件

python 复制代码
import pytest
@pytest.fixture
def file_read():
    print("打开文件句柄")
    fo = open("test.txt", "r", encoding="utf-8")
    yield fo
    print("关闭打开的文件")
    fo.close()

@pytest.fixture
def file_write():
    print("打开文件句柄")
    fo = open("test.txt", "w", encoding="utf-8")
    return fo
    # yield fo
    #
    # print("关闭文件句柄")
    # fo.close()
def test_file(file_write, file_read):
    # 写入数据
    w = file_write
    w.write("测试数据")
    w.close() # 写入后关闭文件句柄,以便读取
    # 读取数据
    r = file_read
    str = r.read(10)
    print("文件内容:", str)

运行:

代码2:

python 复制代码
import pytest
@pytest.fixture
def file_read():
    print("打开文件句柄")
    fo = open("test.txt", "r", encoding="utf-8")
    yield fo
    print("关闭打开的文件")
    fo.close()

@pytest.fixture
def file_write():
    print("打开文件句柄")
    fo = open("test.txt", "w", encoding="utf-8")
    # return fo
    yield fo

    print("关闭文件句柄")
    fo.close()
def test_file(file_write, file_read):
    # 写入数据
    w = file_write
    w.write("测试数据")
    w.close() # 写入后关闭文件句柄,以便读取
    # 读取数据
    r = file_read
    str = r.read(10)
    print("文件内容:", str)

运行:

两个代码的区别是:

python 复制代码
第一个代码:
	return fo

第二个代码:
    yield fo             # 返回文件对象,暂停
    # 测试执行...
    print("关闭文件句柄")  # 测试结束后执行
    fo.close()           # 测试结束后执行

第一个代码:错误

python 复制代码
打开文件句柄  # file_write setup
打开文件句柄  # file_read setup
文件内容: 测试数据  # 测试执行
# 没有teardown执行!文件句柄可能未关闭

第二个代码:正确

python 复制代码
打开文件句柄  # file_write setup
打开文件句柄  # file_read setup
文件内容: 测试数据  # 测试执行
关闭文件句柄  # file_write teardown
关闭打开的文件  # file_read teardown
相关推荐
流星白龙9 小时前
3.接口自动化测试(2)
接口测试
少云清1 天前
【接口测试】5_Postman _Postman请求前置脚本
测试工具·接口测试·postman
2501_924064112 天前
PC软件多系统兼容性测试覆盖策略与不同系统适配方案对比
接口测试
爱尔兰极光2 天前
软件测试--接口测试
接口测试·测试
百度测试开发3 天前
超细整理,性能测试如何做?怎么做?常见面试题(汇总五)
自动化测试·软件测试·软件测试工程师·接口测试·软件测试项目·软件测试面试·性能测试
程序员杰哥3 天前
如何使用Postman做接口自动化测试?
自动化测试·软件测试·python·测试工具·测试用例·接口测试·postman
2501_924064113 天前
2025年优测压测平台与JMeter效率成本对比及行业实践
jmeter·接口测试·压测方案
程序员杰哥4 天前
接口测试之文件上传
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·接口测试
少云清5 天前
【接口测试】5_接口测试基础 _接口文档解析
接口测试·接口文档分析