您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

pytest 前后置操作详谈

时间:2023-04-18 14:11:44  来源:微信公众号  作者:测试玩家勇哥

pytest 的前置与后置处理

Pytest贴心的提供了类似setup、teardown的方法,并且还超过四个,一共有十种

  • 模块级别:setup_module、teardown_module

  • 函数级别:setup_function、teardown_function,不在类中的方法

  • 类级别:setup_class、teardown_class

  • 方法级别:setup_method、teardown_method

  • 方法细化级别:setup、teardown

setup和teardown的详细使用

代码

#!/usr/bin/env Python/ target=_blank class=infotextkey>Python# -*- coding: utf-8 -*-import pytest

def setup_module():    print("=====整个.py模块开始前只执行一次:登录=====")
def teardown_module():    print("=====整个.py模块结束后只执行一次:数据清理=====")
def setup_function():    print("===每个函数级别用例开始前都执行setup_function===")
def teardown_function():    print("===每个函数级别用例结束后都执行teardown_function====")
def test_one():    print("1")
def test_two():    print("2")
class TestCase():    def setup_class(self):        print("====整个测试类开始前只执行一次setup_class====")
    def teardown_class(self):        print("====整个测试类结束后只执行一次teardown_class====")
    def setup_method(self):        print("==测试类里面每个用例执行前都会执行setup_method==")
    def teardown_method(self):        print("==测试类里面每个用例结束后都会执行teardown_method==")
    def setup(self):        print("=测试类里面每个用例执行前都会执行setup=")
    def teardown(self):        print("=测试类里面每个用例结束后都会执行teardown=")
    def test_three(self):        print("3")
    def test_four(self):        print("4")

if __name__ == '__mAIn__':    pytest.main(["-q", "-s", "-ra", "testc.py"])    

运行结果

C:Userschenyongzhi11.virtualenvsapi-test-project-FfYYNBU1Scriptspython.exe D:/apk_api/api-test-project/debug/debug_pytest.py =====整个.py模块开始前只执行一次:登录========每个函数级别用例开始前都执行setup_function===1.===每个函数级别用例结束后都执行teardown_function=======每个函数级别用例开始前都执行setup_function===2.===每个函数级别用例结束后都执行teardown_function========整个测试类开始前只执行一次setup_class======测试类里面每个用例执行前都会执行setup_method==3.==测试类里面每个用例结束后都会执行teardown_method====测试类里面每个用例执行前都会执行setup_method==4.==测试类里面每个用例结束后都会执行teardown_method======整个测试类结束后只执行一次teardown_class=========整个.py模块结束后只执行一次:数据清理=====
4 passed in 0.33s
进程已结束,退出代码0

 

  • 模块级别:模块级别的初始化、清除分别再整个模块的测试用例执行钱后执行,并且只执行一次

  • 类级别:类级别的初始化、清除分别再整个类的测试用例执行前后执行,并且只执行一次

  • 方法级别:方法级别的初始化、清除分别在类的每个测试方法执行前后执行,并且每个用例执行一次

    注:上述都是针对整个脚本全局生效

 

fixture的详细使用

fixture的优势

  • 名命灵活,不局限与setupteardown 的名命

  • coNFTest.py 配置可以实现数据共享,不需要import 就能自动找到fixture

  • scope="module" 实现多py文件共享前置

  • scope="session" 实现多个py文件使用一个session完成多用例

     

fixture参数列表

@pytest.fixture(scope="function", params=None, autouse=False, ids=None, name=None)def test():    print("fixture初始化的参数列表")

参数列表

  • scope:可以理解成fixture的作用域,默认:function,还有class、module、package、session四个【常用】

  • autouse:默认:False,需要用例手动调用该fixture;如果是True,所有作用域内的测试用例都会自动调用该fixture

  • name:默认:装饰器的名称,同一模块的fixture相互调用建议写个不同的name

注意

session的作用域:是整个测试会话,即开始执行pytest到结束测试

测试用例调用fixture的方式

  1. 将fixture名称作为测试用例函数的输入参数

  2. 测试用例加上装饰器:@pytest.mark.usefixtures(fixture_name)

  3. fixture设置autouse=True

    1. 将fixture名称作为测试用例函数的输入参数

import pytest

# 调用方式一@pytest.fixturedef login():    print("输入账号,密码先登录")

def test_s1(login):    print("用例 1:登录之后其它动作 111")

def test_s2():  # 不传 login    print("用例 2:不需要登录,操作 222")

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

结果

============================= test session starts =============================platform win32 -- Python 3.9.5, pytest-7.3.1, pluggy-1.0.0rootdir: D:apk_apiapi-test-projectdebugplugins: Faker-18.4.0collected 2 items
debug_pytest.py 输入账号,密码先登录用例 1:登录之后其它动作 111.用例 2:不需要登录,操作 222.
============================== 2 passed in 0.14s ==============================
进程已结束,退出代码0

方式2:测试用例加上装饰器:@pytest.mark.usefixtures(fixture_name)

import pytest

# 调用方式一@pytest.fixturedef login():    print("输入账号,密码先登录")

# 调用方式二@pytest.fixturedef login2():    print("please输入账号,密码先登录")

@pytest.mark.usefixtures("login2", "login")def test_s11():    print("用例 11:登录之后其它动作 111")

输出:

============================= test session starts =============================collecting ... collected 1 item
teat_learn03.py::test_s11 please输入账号,密码先登录输入账号,密码先登录PASSED                                         [100%]用例 11:登录之后其它动作 111
============================== 1 passed in 0.01s ==============================
Process finished with exit code 0

注意:

  • 在类声明上面加 @pytest.mark.usefixtures() ,代表这个类里面所有测试用例都会调用该fixture

  • 可以叠加多个 @pytest.mark.usefixtures() ,先执行的放底层,后执行的放上层

  • 可以传多个fixture参数,先执行的放前面,后执行的放后面

  • 如果fixture有返回值,用 @pytest.mark.usefixtures() 是无法获取到返回值的,必须用传参的方式(方式一)

  • 方式3:fixture设置autouse=True

  • import pytest
    
    # 调用方式三
    @pytest.fixture(autouse=True)def login3():    print("====所有作用域内的测试用例都会自动调用该fixture===")
    
    def test_s1(login3):    print("用例 1:登录之后其它动作 111")
    
    def test_s2():  # 不传 login    print("用例 2:不需要登录,操作 222")
    
    # 不是test开头,加了装饰器也不会执行fixture@pytest.mark.usefixtures("login3")def loginss():    print(123)
    
    
  • ====所有作用域内的测试用例都会自动调用该fixture===PASSED                                          [ 50%]用例 1:登录之后其它动作 111
    teat_learn03.py::test_s2 ====所有作用域内的测试用例都会自动调用该fixture===PASSED                                          [100%]用例 2:不需要登录,操作 222
    
    ============================== 2 passed in 0.02s ==============================
    
    
fixture的实例化顺序
  • 较高 scope 范围的fixture(session)在较低 scope 范围的fixture( function 、 class )之前实例化【session > package > module > class > function】

  • 具有相同作用域的fixture遵循测试函数中声明的顺序,并遵循fixture之间的依赖关系【在fixture_A里面依赖的fixture_B优先实例化,然后到fixture_A实例化】

  • 自动使用(autouse=True)的fixture将在显式使用(传参或装饰器)的fixture之前实例化

import pytest
order = []

@pytest.fixture(scope="session")def s1():    order.Append("s1")

@pytest.fixture(scope="module")def m1():    order.append("m1")

@pytest.fixturedef f1(f3, a1):    # 先实例化f3, 再实例化a1, 最后实例化f1    order.append("f1")    assert f3 == 123

@pytest.fixturedef f3():    order.append("f3")    a = 123    yield a

@pytest.fixturedef a1():    order.append("a1")

@pytest.fixturedef f2():    order.append("f2")

def test_order(f1, m1, f2, s1):    # m1、s1在f1后,但因为scope范围大,所以会优先实例化    assert order == ["s1", "m1", "f3", "a1", "f1", "f2"]

执行结果:断言成功

关于fixture的注意点

添加了 @pytest.fixture ,如果fixture还想依赖其他fixture,需要用函数传参的方式,不能用 @pytest.mark.usefixtures() 的方式,否则会不生效

@pytest.fixture(scope="session")def open():    print("===打开浏览器===")
@pytest.fixture# @pytest.mark.usefixtures("open") 不可取!!!不生效!!!def login(open):    # 方法级别前置操作setup    print(f"输入账号,密码先登录{open}")

fixture的后置teardown

用fixture实现teardown并不是一个独立的函数,而是用 yield 关键字来开启teardown操作(yield 之前是前置,之后是后置)

import pytest


@pytest.fixture(scope="session")
def open():
    # 会话前置操作setup
    print("===打开浏览器===")
    test = "测试变量是否返回"
    yield test
    # 会话后置操作teardown
    print("==关闭浏览器==")


@pytest.fixture
def login(open):
    # 方法级别前置操作setup
    print(f"输入账号,密码先登录---{open}")
    name = "==我是账号=="
    pwd = "==我是密码=="
    age = "==我是年龄=="
    # 返回变量
    yield name, pwd, age
    # 方法级别后置操作teardown
    print("登录成功")


def test_s2(login):
    print("==用例2==")
    print(login)

 

输出:

============================= test session starts =============================
collecting ... collected 1 item

test_05.py::test_s2 ===打开浏览器===
输入账号,密码先登录---测试变量是否返回
PASSED                                               [100%]==用例2==
('==我是账号==', '==我是密码==', '==我是年龄==')
登录成功
==关闭浏览器==

============================== 1 passed in 0.01s ==============================

 

yield注意事项

  • 如果yield前面的代码,即setup部分已经抛出异常了,则不会执行yield后面的teardown内容

  • 如果测试用例抛出异常,yield后面的teardown内容还是会正常执行

addfinalizer

在用法上,addfinalizer跟yield是不同的,需要你去注册作为终结器使用的函数。

import pytest


@pytest.fixture()
def demo_fixture(request):
    print("n这个fixture在每个case前执行一次")

    def demo_finalizer():
        print("n在每个case完成后执行的teardown")

    # 注册demo_finalizer为终结函数
    request.addfinalizer(demo_finalizer)


def test_01(demo_fixture):
    print("n===执行了case: test_01===")


def test_02(demo_fixture):
    print("n===执行了case: test_02===")


def test_03(demo_fixture):
    print("n===执行了case: test_03===")

 

输出:

============================= test session starts =============================
collecting ... collected 3 items

test_06.py::test_01 
这个fixture在每个case前执行一次
PASSED                                               [ 33%]
===执行了case: test_01===

在每个case完成后执行的teardown

test_06.py::test_02 
这个fixture在每个case前执行一次
PASSED                                               [ 66%]
===执行了case: test_02===

在每个case完成后执行的teardown

test_06.py::test_03 
这个fixture在每个case前执行一次
PASSED                                               [100%]
===执行了case: test_03===

在每个case完成后执行的teardown


============================== 3 passed in 0.04s ==============================

Process finished with exit code 0

 

yield与addfinalizer的区别

1. addfinalizer可以注册多个终结函数。
import pytest

import pytest


@pytest.fixture()
def demo_fixture(request):
    print("n这个fixture在每个case前执行一次")

    def demo_finalizer():
        print("n在每个case完成后执行的teardown")

    def demo_finalizer2():
        print("n在每个case完成后执行的teardown2")

    def demo_finalizer3():
        print("n在每个case完成后执行的teardown3")

    # 注册demo_finalizer为终结函数
    request.addfinalizer(demo_finalizer)
    request.addfinalizer(demo_finalizer2)
    request.addfinalizer(demo_finalizer3)


def test_01(demo_fixture):
    print("n===执行了case: test_01===")


def test_02(demo_fixture):
    print("n===执行了case: test_02===")


def test_03(demo_fixture):
    print("n===执行了case: test_03===")

 

输出:

============================= test session starts =============================
collecting ... collected 3 items

test_06.py::test_01 
这个fixture在每个case前执行一次
PASSED                                               [ 33%]
===执行了case: test_01===

在每个case完成后执行的teardown3

在每个case完成后执行的teardown2

在每个case完成后执行的teardown

test_06.py::test_02 
这个fixture在每个case前执行一次
PASSED                                               [ 66%]
===执行了case: test_02===

在每个case完成后执行的teardown3

在每个case完成后执行的teardown2

在每个case完成后执行的teardown

test_06.py::test_03 
这个fixture在每个case前执行一次
PASSED                                               [100%]
===执行了case: test_03===

在每个case完成后执行的teardown3

在每个case完成后执行的teardown2

在每个case完成后执行的teardown


============================== 3 passed in 0.04s ==============================

Process finished with exit code 0

 

可以看到,注册的3个函数都被执行了,但是要注意的是执行顺序,与注册的顺序相反

2. 当setUp的代码执行错误,addfinalizer依旧会执行

conftest.py的详细讲解

可以理解成一个专门存放fixture的配置文件,如果多个测试用例文件(test_*.py)的所有用例都需要用登录功能来作为前置操作,那就不能把登录功能写到某个用例文件中去了,conftest.py的出现,就是为了解决上述问题,单独管理一些全局的fixture。

conftest.py配置fixture注意事项

  • pytest会默认读取conftest.py里面的所有fixture

  • conftest.py 文件名称是固定的,不能改动

  • conftest.py只对同一个package下的所有测试用例生效

  • 不同目录可以有自己的conftest.py,一个项目中可以有多个conftest.py

  • 测试用例文件中不需要手动import conftest.py,pytest会自动查找

conftest.py使用举例

conftest.py文件(scope=“session”)

import pytest


@pytest.fixture(scope="session")
def login():
    print("输入账号密码")
    yield
    print("清理数据完成")

 

case文件:

import pytest


class TestLogin1():
    def test_1(self, login):
        print("用例1")

    def test_2(self):
        print("用例2")

    def test_3(self, login):
        print("用例3")


if __name__ == '__main__':
    pytest.main()

输出:

输入账号密码
PASSED                                  [ 33%]用例1
PASSED                                  [ 66%]用例2
PASSED                                  [100%]用例3
清理数据完成

 

可以看出,conftest.py内的fixture方法的作用范围是session,调用时,整个.py文件只会调用一次

conftest.py注意事项

  • conftest.py的作用域与Python变量作用域相同

  • 内层包内conftest.py不允许被其它包的测试类或方法使用,相当于本地变量

  • 外层conftest.py可被内层测试类和方法使用,相当于全局变量



Tags:pytest   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
入门Pytest:优雅地进行Python测试
一、引言当涉及到python的测试框架时,pytest是一个功能强大且广泛应用的第三方库。它提供简洁而灵活的方式来编写和执行测试用例,并具有广泛的应用场景。下面是pytest的介绍和...【详细内容】
2023-11-23  Search: pytest  点击:(303)  评论:(0)  加入收藏
掌握Pytest的实用技巧和优秀实践
pytest是一个功能丰富且易于使用的Python测试框架,它建立在Python标准库的unittest模块之上,提供了更简洁、灵活和可读性强的测试代码编写方式。下面,我将按照步骤引导您学习py...【详细内容】
2023-06-07  Search: pytest  点击:(137)  评论:(0)  加入收藏
pytest 前后置操作详谈
pytest 的前置与后置处理Pytest贴心的提供了类似setup、teardown的方法,并且还超过四个,一共有十种 模块级别:setup_module、teardown_module 函数级别:setup_function、teard...【详细内容】
2023-04-18  Search: pytest  点击:(41)  评论:(0)  加入收藏
Pytest 快速入门
Pytest的入门操作使用pytest 特点: 非常容易上手,入门简单,文档丰富,文档中有很多实例可以参考 能够支持简单的单元测试和复杂的功能测试 支持参数化 执行测试过程中可以将...【详细内容】
2023-04-17  Search: pytest  点击:(26)  评论:(0)  加入收藏
pytest通过parametrize方法实现数据驱动实战
前言在之前的篇章中讲解了yaml文件的基本语法规则、yaml文件的读写方法、通过unittest自动化测试框架+ddt+yaml实现数据驱动。同样Pytest自动化测试框架也能读取yaml文件实...【详细内容】
2022-12-03  Search: pytest  点击:(330)  评论:(0)  加入收藏
Python+Pytest框架在Jenkins上生成Allure测试报告
在自动化测试执行之后,生成一个美观大方的测试报告,也是测试过程中,非常最要的一环。测试报告直接反应了测试过程中发现的问题,分析测试报告是解决问题的最重要手段。那么一个专...【详细内容】
2020-07-12  Search: pytest  点击:(803)  评论:(0)  加入收藏
pytest、tox、Jenkins实现python接口自动化持续集成
pytest介绍pytest是一款强大的python测试工具,可以胜任各种级别的软件测试工作,可以自动查找测试用并执行,并且有丰富的基础库,可以大幅度提高用户编写测试用例的效率,具备可扩...【详细内容】
2020-03-16  Search: pytest  点击:(328)  评论:(0)  加入收藏
Python测试工具 | 8 个很棒的pytest插件
Python 测试工具最好的一方面是其强大的生态系统。这里列出了八个最好的插件。我们是 pytest 的忠实粉丝,并将其作为工作和开源项目的默认 Python 测试工具。在本月的 Python...【详细内容】
2019-09-12  Search: pytest  点击:(872)  评论:(0)  加入收藏
▌简易百科推荐
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(5)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(12)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(8)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(10)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(8)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
Kubernetes 究竟有没有 LTS?
从一个有趣的问题引出很多人都在关注的 Kubernetes LTS 的问题。有趣的问题2019 年,一个名为 apiserver LoopbackClient Server cert expired after 1 year[1] 的 issue 中提...【详细内容】
2024-03-15  云原生散修  微信公众号  Tags:Kubernetes   点击:(6)  评论:(0)  加入收藏
站内最新
站内热门
站内头条