python自动化测试之pytest测试框架

该文章已生成可运行项目,

简介

pytest 是 Python 中一个非常流行的‌测试框架‌,主要用于编写、组织和运行单元测试、功能测试和集成测试。它比 Python 自带的 unittest 更简洁、灵活,并且具有丰富的插件生态。Pytest 提供了强大的断言功能,支持丰富的断言表达式,并且在断言失败时会提供详细的错误信息。Pytest 支持大量的插件,这些插件可以扩展 Pytest 的功能,例如支持参数化测试、生成测试报告、与 CI/CD 工具集成等。

安装

pip install pytest

前言

在当前目录和子目录中的所有格式为 test_*.py 或 *_test.py 的文件都被认为是测试文件。pytest要求测试函数的名称以 test 开头,如果函数名称不符合 test_格式,则pytest不会将其视为测试函数。我们不能显式地让pytest将任何不以 _test 开头的函数视为测试函数。

引用

  • 运行所有测试:pytest
  • 运行特定文件:pytest test_sample.py
  • 运行特定测试:pytest test_sample.py::test_answer
  • 显示详细信息:pytest -v
  • 失败时停止:pytest -x
  • 显示打印输出:pytest -s
  • 生成报告:pytest --junitxml=report.xml

插件扩展

  • pytest-cov(测试覆盖率)
  • pytest-xdist(并行测试)
  • pytest-mock(Mock 对象)
  • pytest-asyncio(异步测试)

开始

1.创建以test_开头或结尾的文件

我的写法不规范,请各位规范写法

def tang(x):
    return x + 1

def test_nswera():
    assert tang(3) == 4

def test_buchi():
    assert tang(8) == 9

def test_bu():
    assert tang(5) == 9

 我创建的文件是test_试炼3.py。结果中它找到了3个用例,其中一个错误,两个正确。F代表测试失败,点(.)代表测试成功。各位也可以在终端执行 pytest test_试炼3.py -v 在特定的文件执行测试。

2.再创建一个新的文件

def test_equal():
    num = 100
    assert num == 100  # 测试等于

def test_not_equal():
    num = 100
    assert num != 99   # 测试不等于

def test_range():
    num = 150
    assert 100 < num < 200  # 测试范围区间

 我第二个创建的文件是test_试炼1.py 文件,  pytestste -v是执行你创建文件夹里所有test文件(特定的文件测试,直接加上你的文件名就行)

Pytest 执行一部分测试套件

在实际情况中,我们会有多个测试文件,每个文件都会有多个测试。测试将涵盖各种模块和功能。假设,我们只想运行一组特定的测试;我们该怎么做呢?Pytest提供了两种选择运行测试套件的方法。

1.Pytest 测试名称的子字符串匹配

(pytest -k <substring> -v)里面的<substring>就是你封装的名 ,也就是test_nswera()中的nswera

Pytest 分组测试

介:Pytest允许我们在测试函数上使用标记。标记用于为测试函数设置各种功能/属性。Pytest提供了许多内置的标记,如xfail、skip和parametrize。除此之外,用户还可以创建自己的标记名称。

要点:要使用标记,我们必须在测试文件中导入pytest模块。 我们可以为测试定义自己的标记名称,并运行具有这些标记名称的测试。( @pytest.mark.<markername> )。要运行标记的测试,我们可以使下语法(pytest -m <markername> -v)

  test_试炼2.py

(这是我随便创建的test_开头的文件)


import pytest

@pytest.mark.great
def test_equal():
    num = 100
    assert num == 100

@pytest.mark.great 
def test_not_equal():
    num = 100
    assert num != 99

@pytest.mark.others
def test_list_comparison():
    items = [1, 2, 3]
    assert len(items) > 2

@pytest.mark.others
def test_string_comparison():
    text = "pytest"
    assert len(text) <= 6

@pytest.mark.extreme
def test_boundary():
    value = 999
    assert value < 1000

  test_试炼4.py

import pytest

@pytest.mark.great
def test_identity_comparison():
    lst1 = [1, 2, 3]
    lst2 = lst1
    assert lst1 is lst2

@pytest.mark.others  
def test_collection_contains():
    colors = ["red", "green", "blue"]
    assert "green" in colors

@pytest.mark.extreme
def test_floating_precision():
    result = 1.0 - 0.9
    assert abs(result - 0.1) < 1e-10

现在执行标记为 great 的测试 (pytest -m great -v)以下全部正确

Pytest fixture

介:fixture是在应用于每个测试函数之前运行的函数。fixture用于向测试提供一些数据,比如数据库连接,待测试的URL和一些输入数据。因此,我们可以将固定装置函数附加到测试中,而不是为每个测试运行相同的代码,它将在执行每个测试之前运行并返回数据给测试。


import pytest

@pytest.fixture
def sample_number():
    num = 42
    return num

def test_even_number(sample_number):
    assert sample_number % 2 == 0

def test_divisible_by_7(sample_number):
    assert sample_number % 7 == 0

def test_square_root(sample_number):
    assert sample_number ** 0.5 == pytest.approx(6.4807, rel=1e-4)

 使用命令执行测试 – pytest -k divisible -v

这种方法也有其局限性。在测试文件中定义的装置函数只在该测试文件内部有效。我们无法在另一个测试文件中使用该装置。要使一个装置可用于多个测试文件,我们必须将装置函数定义在一个名为 conftest.py 的文件中。

Pytest Conftest.py

conftest.py 是 pytest 框架中的一个特殊文件,它主要有以下特点:

  • 用于存放 pytest 的 fixture 函数
  • 这些 fixture 可以被同一目录及其子目录中的所有测试文件共享使用
  • 不需要显式导入,pytest 会自动发现这些 fixture
  • 在项目的测试目录中创建一个名为 conftest.py 的文件
  • 在这个文件中定义你的 fixture 函数

换句话理解,可以想象它是一个 ‌"共享工具箱"‌,里面放了一些常用的工具(fixture函数)。任何测试文件(比如 test_*.py)都可以直接使用这些工具,‌不用每次重复写代码‌。

2. 编辑 conftest.py(工具箱)
import pytest

# 定义一个fixture(工具),名字叫"login_data"
@pytest.fixture
def login_data():
    return {"username": "test_user", "password": "123456"}
编辑 test_demo.py(测试文件)
# 注意:这里不需要导入conftest.py!pytest会自动找到它

def test_login(login_data):  # 👈 直接使用fixture名字"login_data"
    print("测试登录,数据是:", login_data)
    assert login_data["username"] == "test_user"

在终端输入:

pytest test_demo.py -v

Pytest 参数化测试

Pytest 参数化测试是一种高效的测试方法,允许你用不同的输入数据运行同一个测试逻辑。@pytest.mark.parametrize 装饰器。最常用的方式,直接在测试函数上标记多组参数:

import pytest

@pytest.mark.parametrize("input,expected", [
    ("3+5", 8),
    ("2*4", 8),
    ("6/2", 3.0)
])
def test_eval(input, expected):
    assert eval(input) == expected

通过运行命令来执行测试:

Pytest -k eval -v

选择xfail测试或跳过测试

在日常写代码中,有些是自己不想要测试的,某个测试在一段时间内不相关,这些情况下,我们可以选择xfail测试或跳过测试。

xfail

xfail测试,它不会被视为失败或通过的部分测试。即使测试失败,也不会打印这些测试的详细信息。我们可以使用标记来xfail测试

skip

跳过测试意味着该测试不会被执行,我们可以使用skip标记来跳过测试

import pytest

@pytest.mark.xfail
@pytest.mark.math
def test_square():
    num = 5
    assert num**2 == 24  # 预期会失败

@pytest.mark.xfail
@pytest.mark.math 
def test_cube():
    num = 3
    assert num**3 == 27  # 预期会通过但标记为xfail

@pytest.mark.skip
@pytest.mark.string
def test_concat():
    s1 = "hello"
    s2 = "world"
    assert s1 + s2 == "helloworld"  # 会被跳过

skipped‌ - 有1个测试用例被跳过(使用了@pytest.mark.skip

xfailed‌ - 有1个测试预期会失败且确实失败了(标记了@pytest.mark.xfail且断言未通过)

xpassed‌ - 有1个测试预期会失败但意外通过了(标记了@pytest.mark.xfail但断言通过了)

warnings‌ - 产生了3条警告信息(可能是弃用警告等)

多或N个测试失败后停止测试套件

在真实的部署场景中,一旦代码的新版本准备就绪,它首先会被部署到预生产或暂存环境中。

随后,会运行一个测试套件对其进行验证。只有当测试套件通过时,代码才被视为准备好部署到生产环境。如果测试中存在一个或多个失败,代码则不能部署到生产环境中。

因此,如果我们希望在出现n个测试失败后立即停止测试套件的执行,可以在pytest中使用  maxfail  选项。

import pytest
import random

import math

def test_cube_success():
    num = 3
    assert num ** 3 == 27  # 3的立方是27,测试通过

def test_addition_success():
    a = 5
    b = 10
    assert a + b == 15  # 5加10是15,测试通过

def test_division_success():
    num = 10
    assert num / 2 == 5  # 10除以2是5,测试通过


def test_random_failure():
    num = random.randint(1, 10)
    assert num > 10  # 必然失败(随机数范围1-10)

def test_string_operation_failure():
    text = "hello"
    assert text.upper() == "HELLO WORLD"  # 大小写转换后长度不匹配

默认情况下,pytest按顺序运行测试。在实际场景中,一个测试套件会有多个测试文件,每个文件会有一系列的测试。这样就会导致较长的执行时间。为了解决这个问题,pytest提供了一个选项来并行运行测试。

为了实现这一点,我们首先需要安装pytest-xdist插件。

pip install pytest-xdist

 -n <num>通过使用多个工作进程来运行测试,这里是3

pytest -n 3

 还有一个生成结果的,xml,我这里就不多讲了,感兴趣的可以去了解一下。

pytest -v --junitxml = "result.xml"

总结

Pytest 是一个功能强大且易于使用的测试框架,适用于各种规模的 Python 项目。通过掌握其基本功能和高级特性,可以显著提高测试效率和代码质量。

该文章已生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值