pytest基本使用

1、pytest安装

(1)、doc命令行安装

安装:pip install pytest==5.4.3

查看:pip show pytest

2、项目中安装

File --》setting--》project,搜索pytest可选需要版本点击install

2、pytest使用规则及运行方式

使用pytest用例必须遵守以下规则

  • 测试文件名必须以test开头或者test结尾
  • 测试方法必须以test开头
  • 测试类名以Test开头(首字母大写),里面不包含__init__方法
  • 所有包Package必须包含__init__.py文件
  • 断言使用基本的assert即可

(1)、命令行执行

执行该目录下所有用例:pytest或者py.test

单独执行一个模块:pytest -s 文件名.py

运行模块中单独的类:pytest 文件名.py::类名

运行模块中某个类的某个方法::pytest 文件名.py::类名::方法名

用例执行的参数:

-s 表示支持控制台打印,如果不加,print 不会出现任何内容、

-v 打印运行日志信息,详细

-q 打印运行日志信息,简略

运行示例:pytest -s test_demo.py

(2)、主函数执行

pytest.mian()
main函数有2个可选参数:
args:命令行参数列表。
plugins:初始化期间要自动注册的插件对象列表。

python 复制代码
import pytest
class Test:

    def test_case01(self):
        print(1)

    def test_case02(self):
        print(2)
if __name__ == "__main__":
    pytest.main(["-s","test_demo."])

运行结果

. 表示成功 F 表示失败

小结

建议使用命令行的形式运行,对比主函数模式更加方便

(3)、pycharm工具执行

可以使用右键执行

3、pytest的前后置setup teardown

pytest 在运行自动化脚本的前后会执行两个特殊的方法,分别是 setup 和 teardown

在执行脚本之前会执行 setup方法,在执行脚本之后会执行 teardown 方法

我们可以在 setup 中进行获取驱动对象的操作,在teardown 中进行关闭驱动对象的操作

应用场景

函数级别方法

运行于测试方法的始末,运行一次测试函数会运行一次 setup 和 teardown。

python 复制代码
import pytest

class Test:

    def setup(self):
        print('test--->setup')
    def teardown(self):
        print('test--->teardown')
    def test_case01(self):
        print('test--->1')

    def test_case02(self):
        print('test--->2')


# 主函数执行

if __name__ == '__main__':
    pytest.main(['-s','test_demo01.py'])

执行结果

类级别方法

python 复制代码
import pytest

class Test:

    def setup_class(cls):
        print('test--->setupcls')
    def teardown_class(cls):
        print('test--->teardowncls')
    def test_case01(self):
        print('test--->1')

    def test_case02(self):
        print('test--->2')


# 主函数执行

if __name__ == '__main__':
    pytest.main(['-s','test_demo01.py'])

运行结果

4、Pytest-html测试报告

应用场景

复制代码
自动化测试脚本最终执行是通过还是不通过,需要通过测试报告进行体现

使用命令进行安装 指定版本

复制代码
pip install pytest-html==2.1.1

执行命令

复制代码
pytest test_login.py --html=report.html

报告展示

6、函数执行顺序

应用场景

现实生活中,如果想下订单,必须先登录,我们可以通过插件的形式来控制函数执行的顺序

安装

复制代码
使用命令 pip3 install pytest-ordering
  • 标记于被测试函数,@pytest.mark.run(order=x)

  • 根据order传入的参数来解决运行顺序

  • order值全为正数或全为负数时,运行顺序:值越小,优先级越高

  • 正数和负数同时存在:正数优先级高

  • 示例代码

python 复制代码
import pytest
​
class Test:
​
    def test_case01(self):
        print('test--->001')
​
    @pytest.mark.run(order=2)
    def test_case02(self):
        print('test--->002')
​
    @pytest.mark.run(order=1)
    def test_case03(self):
        print('test--->003')
  • 执行结果

5、 失败重试

应用场景

复制代码
由于网络的原因造成自动化脚本报错,我们可以使用失败重试的插件,当失败后尝试再次运行,一般情况最终成功可以视为成功,但最好进行进行排查时候是脚本问题

安装

复制代码
使用命令 pip3 install pytest-rerunfailures 进行安装使用

在配置文件中的命令行参数中增加 --reruns n 失败重跑次数3 失败后延迟1秒

复制代码
pytest  -s test_demo2.py --reruns 3 --reruns-delay 1
  • 示例代码
python 复制代码
class Test:
​
    def test_a(self): 
        assert 1,1 # 断言成功
​
    def test_b(self):
        print('失败')
        assert 0,1 # 断言失败
  • 运行结果

R 表示重试

注意重试时,如果脚本通过,那么后续不再重试

6、跳过测试函数

复制代码
调试时不运行这个用例
无法再某些平台上运行的测试功能
有些版本中不支持
当前外部资源不可用

使用方式

复制代码
在需要跳过的测试脚本之上加上装饰器  @pytest.mark.skip(reason="当前设备不支持"),也可以增进条件判断是否跳过 @pytest.mark.skipif(age<5,reason="少于10年工作经验不考虑录取")
  • 示例代码

    python 复制代码
    class Test:
    ​
        def test_a(self): 
            assert 1,1 # 断言成功
        @pytest.mark.skip(reason="当前设备不支持")
        def test_b(self):
            print('失败')
            assert 0,1 # 断言失败
  • 执行结果

7、预期失败

应用场景

功能尚未实施或尚未修复的错误,结果会预计失败、你希望的某种情况应该失败

举例,测试手机号码输入框长度为11位数字,如果我们传入一个 12 位数字,此时可以使用预期失败@pytest.mark.xfail()

使用方式在需要标记预期失败的测试脚本之上加上装饰器示例

  • 示例代码
python 复制代码
class Test:
​
    def test_a(self):
        print('-----testa')
        assert 1,1 # 断言成功
​
    @pytest.mark.xfail()
    def test_b(self):
        print('-----testb')
        assert 0,1 # 断言失败
​
    @pytest.mark.xfail()
    def test_c(self):
        print('-----testc')
        assert 0, 2  # 断言失败
  • 执行结果

x 表示预期失败结果失败 不算是bug, X 表示预期失败结果成功 算是bug

8、数据参数化

应用场景

登录功能都是输入用户名,输入密码,点击登录。但登录的用户名和密码如果想测试多个值是没有办法用普通的操作无法实现的。数据参数化可以帮我实现这样的效果。

方法名

复制代码
@pytest.mark.parametrize(argnames, argvalues)

argnames 参数名

argvalues 参数对应值,类型必须为可迭代类型,一般使用list

一个参数使用方式

  1. argnames 为字符串类型,根据需求决定合适的参数名

  2. argvalues 为列表类型,根据需求决定列表元素中的内容

  3. 在测试脚本中,参数,名字与 argnames 保持一致

  4. 在测试脚本中正常使用argvalues 列表有多少个内容,这个脚本就会运行几次

  • 示例代码
python 复制代码
class Test:
​
    @pytest.mark.parametrize('age',[18,19,23,21])
    def test_01(self,age):
        print(age)
  • 执行结果

多个参数

  • 示例代码
python 复制代码
class Test:
​
    @pytest.mark.parametrize(('name','age'),[('zhangsan',18),('lisi',19)])
    def test_01(self,name,age):
        print(name,age)
  • 执行结果

9、 Pytest-fixture

一. 前置处理(setup)

应用场景

fixture 修饰器来标记固定的函数,在其他函数,类调用它时会被激活并优先执行,通常会被用于完成预置处理和重复操作

使用方式

​ 通过函数引用

  • 示例代码:例如用户A需要登录,用户B不需要登录,用户C需要登录,此时用setup().teardown()方法处理不太合适。这种方式还能被用来接口关联传参
python 复制代码
class Test_fixture:
​
    @pytest.fixture()
    def login(self):
        print('登录操作')
        uname = 'lily'
        return uname
​
    def test_a(self,login):
        print(f'test_a{login}')
​
    def test_b(self):
        print('不需要登录')
​
    def test_c(self,login):
        print(f'test_c{login})')
  • 运行结果

pytest 中,fixture 是一种非常强大的功能,用于管理测试用例的前置条件(如初始化资源)和后置处理(如清理资源),可以实现代码复用、测试环境隔离等效果。它比传统的 setup/teardown 更灵活,支持参数化、依赖注入等高级特性。

python 复制代码
import pytest

# 定义一个简单的 fixture
@pytest.fixture
def demo_fixture():
    print("\n执行 fixture 前置操作")
    # 返回测试数据或资源
    return "fixture 提供的数据"

# 测试用例使用 fixture(直接将 fixture 名称作为参数传入)
def test_use_fixture(demo_fixture):
    print(f"测试用例获取到的数据:{demo_fixture}")
    assert demo_fixture == "fixture 提供的数据"

执行结果:

python 复制代码
执行 fixture 前置操作
测试用例获取到的数据:fixture 提供的数据
.

二. 后置处理(teardown)

如果需要在测试用例执行后清理资源(如关闭浏览器、断开数据库连接),可以使用 yield 关键字分隔前置和后置逻辑。yield 之前的代码是前置操作,之后的代码是后置操作。

python 复制代码
import pytest

@pytest.fixture
def browser():
    print("\n前置:启动浏览器")
    driver = "模拟浏览器实例"  # 实际中可能是 webdriver.Chrome()
    yield driver  # 返回资源给测试用例
    print("\n后置:关闭浏览器")  # 测试用例执行后自动执行

def test_browse(browser):
    print(f"测试中使用浏览器:{browser}")
    assert browser == "模拟浏览器实例"

执行结果:

plaintext

python 复制代码
前置:启动浏览器
测试中使用浏览器:模拟浏览器实例
.
后置:关闭浏览器

三、fixture 作用域(scope)

通过 scope 参数可以控制 fixture 的作用域,即 fixture 被创建和销毁的时机。常用的作用域有:

scope 值 说明 适用场景
function 每个测试函数执行一次(默认) 每次测试需要全新资源(如浏览器)
class 每个测试类执行一次 类内所有用例共享资源
module 每个模块(.py 文件)执行一次 模块内所有用例共享资源
package 每个包执行一次 包内所有用例共享资源
session 整个测试会话(一次 pytest 执行)执行一次 所有用例共享资源(如数据库连接)

示例:作用域为 session 的 fixture(全局只初始化一次)

python

运行

python 复制代码
import pytest

@pytest.fixture(scope="session")
def db_connection():
    print("\n前置:建立数据库连接")
    conn = "模拟数据库连接"
    yield conn
    print("\n后置:关闭数据库连接")

# 模块内的多个用例共享该 fixture
def test_query(db_connection):
    print(f"使用连接 {db_connection} 执行查询")

def test_insert(db_connection):
    print(f"使用连接 {db_connection} 执行插入")

执行结果(连接只建立和关闭一次):

plaintext

python 复制代码
前置:建立数据库连接
使用连接 模拟数据库连接 执行查询
.使用连接 模拟数据库连接 执行插入
.
后置:关闭数据库连接

四、fixture 依赖与参数化

1. 依赖其他 fixture

一个 fixture 可以依赖另一个 fixture,只需在定义时将被依赖的 fixture 名称作为参数传入。

python 复制代码
import pytest

@pytest.fixture
def user():
    return {"name": "张三", "age": 20}

# 依赖 user fixture
@pytest.fixture
def user_profile(user):
    return f"用户信息:{user['name']},{user['age']}岁"

def test_user_profile(user_profile):
    assert user_profile == "用户信息:张三,20岁"
2. 参数化 fixture(params

通过 params 参数可以为 fixture 传入多组数据,测试用例会自动根据参数生成多个用例。

python

运行

python 复制代码
import pytest

# 传入多组参数,fixture 会被调用多次
@pytest.fixture(params=["Chrome", "Firefox", "Edge"])
def browser(request):  # request 是 pytest 内置 fixture,用于获取参数
    browser_name = request.param  # 获取当前参数
    print(f"\n启动浏览器:{browser_name}")
    yield browser_name
    print(f"\n关闭浏览器:{browser_name}")

def test_browser(browser):
    print(f"测试浏览器:{browser}")

执行结果(会生成 3 个测试用例):

plaintext

python 复制代码
启动浏览器:Chrome
测试浏览器:Chrome
.
关闭浏览器:Chrome

启动浏览器:Firefox
测试浏览器:Firefox
.
关闭浏览器:Firefox

启动浏览器:Edge
测试浏览器:Edge
.
关闭浏览器:Edge

fixture数据驱动

python 复制代码
@pytest.fixture(params=get_promo_data().keys(), ids=lambda x: f"country_{x}")
def country_data(request):
    promo_data = get_promo_data()
    return promo_data[request.param]
  1. params=get_promo_data().keys()
  • get_promo_data() 是读取 country_promo.json 的函数,返回的是一个字典(键为国家代码,如 "us""jp")。
  • .keys() 获取字典的所有键(即国家代码列表,如 ["us", "jp", "de"...])。
  • params 参数接收这个列表,使 fixture 会为每个国家代码生成一个独立的实例(即每个国家对应一个 fixture 实例)。
  1. ids=lambda x: f"country_{x}"
  • ids 用于为每个参数化实例指定一个唯一标识 ,在测试报告中显示,替代默认的 param0param1 等。
  • lambda x: f"country_{x}" 是一个匿名函数,将国家代码 x 转换为 country_uscountry_jp 等标识,更直观区分不同国家的用例。
  1. request.param
  • request 是 pytest 内置的 fixture,用于获取当前参数化的上下文。
  • request.param 表示当前迭代的参数值(即某个国家代码,如 "us")。
  • 函数返回 promo_data[request.param],即该国家代码对应的完整数据(如 us 对应的本地语言、文案等信息)。

实际效果

假设 get_promo_data().keys() 返回 ["us", "jp", "de"],则:

  • 该 fixture 会生成 3 个实例,分别对应 usjpde
  • 测试报告中用例标识为 country_uscountry_jpcountry_de
  • 测试用例中使用 country_data 时,会自动接收对应国家的完整数据(如 us 的本地语言、文案等)。

测试用例中使用示例

python 复制代码
def test_promo(country_data):
    # country_data 会依次接收 us、jp、de 对应的完整数据
    print(f"测试国家: {country_data['country_name']}")
    print(f"本地语言文案: {country_data['local_content']['tab_text']}")

执行后会生成 3 个用例,分别测试美国、日本、德国的大促数据,报告中清晰显示每个用例对应的国家。

核心价值

  1. 数据驱动:通过 JSON 数据自动生成多国家测试用例,无需手动编写重复代码。
  2. 用例标识清晰ids 自定义命名使报告更易读,快速定位某个国家的测试结果。
  3. 数据与用例分离:国家数据通过 JSON 管理,修改或新增国家只需更新数据文件,无需改动代码。

五、自动使用 fixture(autouse

如果希望某个 fixture 被所有测试用例自动使用(无需在测试函数参数中显式声明),可以设置 autouse=True

python

运行

python 复制代码
import pytest

# 自动应用到所有用例
@pytest.fixture(autouse=True, scope="function")
def log_test_start():
    print("\n===== 测试开始 =====")
    yield
    print("\n===== 测试结束 =====")

def test_case1():
    print("执行测试用例 1")

def test_case2():
    print("执行测试用例 2")

执行结果:

plaintext

python 复制代码
===== 测试开始 =====
执行测试用例 1
.
===== 测试结束 =====

===== 测试开始 =====
执行测试用例 2
.
===== 测试结束 =====

五、fixture 复用(conftest.py

如果多个测试模块需要共享 fixture,可以将 fixture 定义在 conftest.py 文件中(无需导入,pytest 会自动识别)。

项目结构:

plaintext

python 复制代码
tests/
├── conftest.py  # 存放共享 fixture
├── test_module1.py
└── test_module2.py

conftest.py 内容:

python 复制代码
import pytest

@pytest.fixture
def common_data():
    return "共享数据"

test_module1.py 内容:

复制代码
def test_use_common(common_data):  # 直接使用 conftest 中的 fixture
    assert common_data == "共享数据"

总结

  • fixture 用于管理测试的前置 / 后置逻辑,替代传统 setup/teardown
  • 核心特性:作用域(scope)、后置处理(yield)、参数化(params)、自动使用(autouse)。
  • 通过 conftest.py 实现 fixture 跨模块复用。
  • 在 UI 自动化中,常用 fixture 管理浏览器驱动(如启动 / 关闭浏览器),在接口测试中管理数据库连接或登录令牌等。

10、Allure的使用

应用场景:Allure是一个独立的报告插件,可以用来生成自动化测试报告,目前支持Python、Java、PHP、C#

1、Allure的安装

安装方式:window可以直接将安装包位置的bin目录路径配置在环境变量下即可如:D:\software\pycharm\allure-2.10.0\bin

查看是否配置成功:查看安装版本

安装插件:pip install allure-pytest==2.8.16
最终我们会生成一个 html 格式的报告,中间我们需要操作两步来进行

  • 执行生成json,指定结果保存目录

    • pytest --alluredir=report test_demo.py

查看测试报告方式

  • 将json转成 html ,使用allure generate生成html格式的测试报告

    • 进入 report 上级目录执行命令

    • allure generate report/ -o report/html --clean

    • report 目录下会生成 html 文件夹,html 下会有一个 index.html ,右键用浏览器打开即可

      allure generate report/ -o report/html --clean 是什么意思?

      复制代码
      report/ 表示 xml 所在的目录
      ​
      -o 表示 output 输出
      ​
      --clean 覆盖路径
      ​
      report/html 表示将 index.html 报告生成到哪个文件夹

2、 Allure 与 Pytest 结合

2.1 添加测试步骤
复制代码
@allure.step(title='不需要登录')
def test_b(self):
    print('不需要登录操作')报告显示:
2.2 添加主要功能模块描述
复制代码
@allure.feature('testa模块')
def test_a(self,test_login):
    print(f'test_a {test_login}')

报告显示:

2.3 添加严重等级

参数有五个,也对应不同的优先级,只需要将最后一个词替换即可

  • BLOCKER 最严重

  • CRITICAL 严重

  • NORMAL 普通

  • MINOR 不严重

  • TRIVIAL 最不严重

复制代码
@allure.severity(allure.severity_level.TRIVIAL)
def test_c(self,test_login):
    print(f'testc {test_login}')
复制代码
@allure.severity(allure.severity_level.CRITICAL)
@allure.feature('testa模块')
def test_a(self,test_login):
    print(f'test_a {test_login}')

报告显示:

3、添加测试截图到allure

allure.attach(screenshot, name=name, attachment_type=allure.attachment_type.PNG) 是 Allure 报告框架中用于将二进制格式的截图(或其他文件)附加到测试报告的方法,常用于在报告中直观 地展示测试过程中的页面状态(尤其是失败场景),辅助问题定位。

核心作用

  • 直接将内存中的二进制数据(如截图的 PNG 二进制流)作为附件添加到 Allure 报告中,无需先保存为本地文件。
  • driver.get_screenshot_as_png() 配合使用时,可快速将当前页面截图嵌入报告,避免额外的文件 IO 操作。

参数解析

  1. screenshot :必传参数,需要附加的二进制数据 (如 PNG 图片的二进制流)。在 Selenium 中,通常通过 driver.get_screenshot_as_png() 获取当前页面的二进制截图,例如:

    python

    运行

    复制代码
    screenshot_binary = driver.get_screenshot_as_png()  # 返回 PNG 格式的二进制数据
  2. name :可选参数,附件在报告中显示的名称(建议清晰描述场景,如 "美国站大促 Tab 验证失败"),便于识别。

  3. attachment_type :必传参数,指定附件的类型 ,由 allure.attachment_type 提供,常见类型包括:

    • allure.attachment_type.PNG:PNG 图片(最常用,对应截图)
    • allure.attachment_type.TEXT:文本内容
    • allure.attachment_type.JSON:JSON 数据

典型用法(结合 Selenium 截图)

在测试失败时,捕获页面截图的二进制数据,直接附加到 Allure 报告:

python

运行

复制代码
import allure
from selenium import webdriver

driver = webdriver.Chrome()

try:
    driver.get("https://example.com/promo/us")
    # 执行测试步骤(如验证大促Tab名称)
    actual_tab = driver.find_element("id", "promo_tab").text
    assert actual_tab == "Black Friday"
except AssertionError as e:
    # 获取当前页面的二进制截图
    screenshot = driver.get_screenshot_as_png()
    # 附加截图到Allure报告,名称为"美国站大促Tab验证失败"
    allure.attach(screenshot, name="美国站大促Tab验证失败", attachment_type=allure.attachment_type.PNG)
    # 抛出异常,标记用例失败
    raise e
finally:
    driver.quit()

allure.attach.file() 的区别

  • allure.attach():直接处理二进制数据,无需生成本地文件,适合临时截图或动态数据,减少磁盘操作。
  • allure.attach.file() :需要传入本地文件路径(如 ./screenshots/error.png),从文件读取数据附加到报告,适合已保存的截图或日志文件。

在你的大促自动化场景中,若需快速将各国大促页面的验证结果(成功 / 失败)截图嵌入报告,allure.attach() 配合 driver.get_screenshot_as_png() 是更高效的选择,既省去了保存本地文件的步骤,又能让报告更直观地展示问题。

报告展示效果

在 Allure 报告的 "Attachments" 区域,会显示附加的截图,点击即可查看大图,例如:

  • 名称:"美国站大促 Tab 验证失败"
  • 内容:失败时的页面截图,可直观看到实际显示的 Tab 名称与预期不符。

这对于非技术人员(如运营、产品)查看测试结果非常友好,能快速定位大促素材的展示问题。

相关推荐
阿关@6 小时前
Vscode中Python无法将pip/pytest”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
vscode·python·pip
Kristen_YXQDN6 小时前
PyCharm 中 pytest 运行 python 测试文件报错:D:\Python_file\.venv\Scripts\python.exe: No module named pytest
运维·开发语言·python·pycharm·pytest
Low--Key6 小时前
pytest框架快速入门
python·自动化·pytest
IMPYLH6 小时前
Lua 的 Debug(调试) 模块
开发语言·笔记·python·单元测试·lua·fastapi
姜西西_6 小时前
自动化测试框架pytest之fixture
android·java·pytest
普通网友7 小时前
更优雅的测试:Pytest框架入门
jvm·数据库·python
测试开发Kevin7 小时前
超级实用!汇总pytest中那些常用的参数
单元测试·pytest
Beaman10247 小时前
pytest框架
python·pytest