pytest自动化测试中的fixture的声明和调用

目录
  • 1. fixture的声明
  • 2. fixture的调用
    • 2.1 fixture的调用方式
      • 2.1.1 使用fixturename
      • 2.1.2 使用@pytest.mark.usefixtures("fixturename")
      • 2.1.3 autouse——自动应用
    • 2.2 fixture使用的灵活性
      • 2.2.1 一个fixture函数可以调用其他的fixture
      • 2.2.2 fixture函数可被反复重用
      • 2.2.3 测试函数/fixture函数可以一次调用多个fixture
      • 2.2.4 同一测试执行期间,fixture可被多次请求

1. fixture的声明

我们使用@pytest.fixture()来声明fixture函数。fixture()即可无参数进行声明,也可以带参数声明。

示例1:

@pytest.fixture()无参数进行声明

import pytest
@pytest.fixture      #fixture()未带任何参数,声明一个fixture函数
def fixture_demo():
    print("这个是一个fixture的demo演示")
def test_demo(fixture_demo):  #调用fixture函数——fixture_demo
    print("这是一个测试demo。")

@pytest.fixture()有参数的进行声明
通过上文pytest中fixtureAPI简单说明,我们对fixture()的参数有了一定了解。fixture()可以带着这些参数去声明一个fixture函数。

import pytest
@pytest.fixture(params=[1,2,3]) #fixture()带着parmas对ids()进行fixture函数的声明
def ids(request):
    data=request.param
    print(f'获取测试数据{data}')
    return data
def test_ids(ids):  #调用fixture函数-ids()
    print(ids)

2. fixture的调用

2.1 fixture的调用方式

fixture有三种调用方式,分别为:

1. 使用 fixturename
2. 使用@pytest.mark.usefixtures(“fixturename”)
3. autouse——自动应用

2.1.1 使用fixturename

通过pytest中fixtureAPI简单说明中对@fixture()参数的介绍,我们知道fixturename默认是@pytest.fixture()所装饰的函数的函数名,如果传入name参数,则fixturename就是name传入的内容。

当要调用fixture的时候,只要将fixturename作为参数传入测试函数即可。

示例2:

1.使用被装饰的函数的函数名

import pytest
@pytest.fixture() #未传入name,因此fixturename为函数名login
def login():
    print('login')
def test_case1(login):  #将fixturename作为参数传入
    print('这是testcase1')

2.使用fixture别名

import pytest
@pytest.fixture(name='login1') #传入name,因此fixturename为login1
def login():
    print('login')
def test_case1(login1):  #将fixturename作为参数传入
    print('这是testcase1')

注意:
当使用fixture的别名后,被装束函数的函数名失效,无法再继续使用其进行fixture的调用。

2.1.2 使用@pytest.mark.usefixtures("fixturename")

根据pytest官方文档的介绍,如果想让某个fixture适用于类、模块和项目中所有测试函数的话,会使用usefixtures来调用fixture。当然,单个测试函数也可以使用此方法来调用fixture。

使用usefixtures调用fixture和直接使用fixturename来调用fixture是有区别的,可总结为:

使用usefixtures调用的fixture只能用于配置测试前系统的初始状态,无法为测试用例提供测试数据;但使用fixturename调用的fixture却可以实现这两个功能。

示例:
1.声明一个名为login的fixture,并通过fixture()传入测试数据集。test_case1使用usefixtures的方法调用login,并且在函数内部想要打印login的返回值。

import pytest
@pytest.fixture(params=[1,2,3])  # 传入测试数据集
def login(request):
    print("登陆操作")
    return request.param #返回测试数据
class TestClass1:
    @pytest.mark.usefixtures('login')  #使用usefixtures调用login
    def test_case1(self):
        print("这是Testclass1中testcase1")
        print(login)  #打印login

运行后发现,结果和我们预期的不一样,print(login)打印出的是函数对象信息,不是返回值。

2.修改刚刚的代码,使用fixturename来调用login

import pytest
@pytest.fixture(params=[1,2,3])  # 传入测试数据集
def login(request):
    print("登陆操作")
    return request.param #返回测试数据
class TestClass1:
    #@pytest.mark.usefixtures('login')  #使用usefixtures调用login
    def test_case1(self,login): #使用fixturename的方式调用login
        print("这是Testclass1中testcase1")
        print(login)  #打印login

运行后我们可以发现,结果和我们预期的一致,把login的返回值成功打印出来。

usefixtures调用fixture的方法只适用于测试函数,对于fixture函数不生效;使用fixturename调用fixture的方法对测试函数和fixture函数都适用。

示例:
1.以下demo想要实现执行测试用例前打印“登陆操作”,用例执行结束后打印“注销操作”。声明loginlogout为fixture函数,并且让logout使用usefixtures的方法调用login,再让test_case1调用logout

import pytest
@pytest.fixture()
def login():
    print("登陆操作")
@pytest.mark.usefixtures('login') @pytest.fixture() def logout():
    yield
    print("注销操作")
class TestClass1:
    def test_case1(self,logout):
        print("这是Testclass1中testcase1")

通过运行结果我们发现,结果只在执行测试函用例后打印了“注销操作”,与我们预期的结果不一致。

2.修改上面的demo代码,让logout使用fixturename的方式调用login

import pytest
@pytest.fixture()
 def login():
    print("登陆操作")
#@pytest.mark.usefixtures('login')
@pytest.fixture()
def logout(login): #使用fixturename的方式调用login
    yield
    print("注销操作")
class TestClass1:
    def test_case1(self,logout):
        print("这是Testclass1中testcase1")

运行后我们发现,结果与我们预期的一致。

由此可以看出来,userfixtures的调用方法对于fixture函数无效。

下面我们将通过示例来演示userfixtures的使用方法:

为了演示效果,我们新建一个包,并在里面创建一个conftest.py。用于定义fixture函数。关于conftest.py的相关内容,后面会单独写一遍文章详细介绍。

在conftest.py中声明的一个login函数。

import pytest
@pytest.fixture()
def login():
    print('登录操作')

1.整个类中应用fixture

使用usefixtures,让TestClass1这个类中所有测试函数都调用login

import pytest
@pytest.mark.usefixtures('login')  #让TestClass1调用login
class TestClass1:
    def test_case1(self):
        print("这是Testclass1中testcase1")
    def test_case2(self):
        print('这是Testclass1中testcase2')
class TestClass2:
    def test_case3(self):
        print('这是Testclass2中的testcase3')

运行结果:

通过结果我们可以发现,只有TestClass1中的test_case1和test_case2调用了login。

2.整个模块应用fixture

根据官方文档说明,在整个模块中应用fixture,可在模块使用

pytestmark=pytest.mark.usefixtures("fixturename")。

修改测试代码如下:

import pytest
pytestmark = pytest.mark.usefixtures("login")  #使用pytestmark在模块中使用usefixtures
class TestClass1:
    def test_case1(self):
        print("这是Testclass1中testcase1")
    def test_case2(self):
        print('这是Testclass1中testcase2')
class TestClass2:
    def test_case3(self):
        print('这是Testclass2中的testcase3')

运行结果:

通过运行结果可发现,整个模块中,所有测试类里面的测试函数都调用了login。

3.整个项目中使用

pytest.ini中配置usefixtures

演示项目结构如图:

对应文件中的代码如下:

test_demo中的test_demo.py

class TestClass1:
    def test_case1(self):
        print("这是pytest_demo包中test_demo模块里Testclass1中testcase1")
class TestClass2:
    def test_case2(self):
        print('这是pytest_demo包中test_demo模块里Testclass2中的testcase2')

test_usefixtures中的test_usefixtures.py

class TestClass1:
    def test_case1(self):
        print("这是pytest_usefixtures包中test_usefixtures模块里Testclass1中testcase1")
class TestClass2:
    def test_case2(self):
        print('这是pytest_usefixtures包中test_usefixtures模块里Testclass2中的testcase2')

TestDemo根目录下的conftest.py

import pytest

@pytest.fixture()
def login():
    print('登录操作')

TestDemo根目录下的pytest.ini

[pytest]
usefixtures = login

运行整个项目:

项目中的测试函数都调用了conftest.py中的login。

4.使用usefixtures调用多个fixture

我们可以使用@pytest.mark.usefixtures('fixturename1','fixturename2')来调用多个fixture。

conftest.py中新增一个fixture:

import pytest
@pytest.fixture()
def login():
    print('登录操作')
@pytest.fixture()
def printids():
    print("打印ids。")

修改test_usefixtures.py:

@pytest.mark.usefixtures('login','printids')
class TestClass1:
    def test_case1(self):
        print("这是pytest_usefixtures包中test_usefixtures模块里Testclass1中testcase1")

运行后结果:

test_case1测试函数调用loginprintids两个fixture。

2.1.3 autouse——自动应用

fixture()autouse参数,是fixture自动应用的标识。

如果autouse=True,则在同作用域下的测试函数,会自动调用该fixture;如果autouse=False,则测试函数需要主动去调用该fixture。

autouse默认是False

示例4:

1.在TestClass1这个类中定义了一个login函数,声明为fixture,并且autouse设置为True

TestClass1中的test_case1主动调用了login,但是其他测试函数未主动调用。

我们还写了一个TestClass2类,类中有一个test_case4的测试函数。

import pytest
class TestClass1:
    @pytest.fixture(autouse=True)  # 启用自动应用
    def login(self):
        print("登陆操作")
    def test_case1(self,login):  # 调用了login这个fixture函数
        print("这是Testclass1中testcase1")
    def test_case2(self):  # 没有调用
        print('这是Testclass1中testcase2')
    def test_case3(self):  # 没有调用
        print('这是Testclass1中testcase3')
class TestClass2:
    def test_case4(self):
        print('这是Testclass2中的testcase4')

运行结果:

通过运行结果我们可以知道,当fixture的autouse=True的时候,在同作用域内的测试函数会自动调用fixture,非同作用域内的测试函数无法调用。

2.我们给fixture()带上更多的参数,修改上面的demo,并设置fixture的scope=‘class'

import pytest
@pytest.fixture(scope='class', autouse=True)  # fixture的作用域设为class级别,启用自动应用
def login():
    print("登陆操作")
class TestClass1:
    def test_case1(self):
        print("这是Testclass1中testcase1")
    def test_case2(self):
        print('这是Testclass1中testcase2')
    def test_case3(self):
        print('这是Testclass1中testcase3')
class TestClass2:
    def test_case4(self):
        print('这是Testclass2中的testcase4')

运行结果:

通过运行结果我们可以看出,当设置loginscope=‘class'的使用,每一个测试类都会自动调用一次login

autouse的使用也是遵照fixture函数的设置来进行的。

2.2 fixture使用的灵活性

通过官方文档的说明,我们知道了pytest的fixture系统是极其的灵活和强大的,官方文档也为我们以下几个灵活使用fixture的例子。

2.2.1 一个fixture函数可以调用其他的fixture

文章前面我们有演示过一个fixture函数调用其他fixture的例子。

代码如下:

import pytest
@pytest.fixture()
 def login():
    print("登陆操作")
@pytest.fixture()
def logout(login):
    yield
    print("注销操作")
class TestClass1:
    def test_case1(self,logout):
        print("这是Testclass1中testcase1")

login()实现了测试执行的前置操作,logout()实现了测试执行的后置操作。logout()调用了login,测试函数则直接调用了logout

fixture在执行的时候是依次执行的。假如fixture A 调用了fixture B,那么执行的时候会先执行fixture B,然后再执行fixture A。因为fixture B是fixture A的依赖条件。

所以我们运行上面代码的时候,是会先调用login()然后再调用logout()的。而logout()中的yield会让测试用例执行的时候先执行login中的测试前置操作,然后再执行测试用例中的内容,最后执行logoutyield后面测试后置操作。

这样的一个操作,可以将复杂的测试需求,变成一个一个简单而又有组织性的的功能函数,更加方便后期进行维护。

2.2.2 fixture函数可被反复重用

两个不同的测试函数可以调用同一个fixture,并且获得各自的运行结果。测试函数之间并不会因为调用了同一个fixture而相互之间产生任何影响。

示例5:

演示代码:

import pytest
@pytest.fixture()
def first_number():  #fixture函数,返回1
    return 1
@pytest.fixture()
def order(first_number): #fixture函数,调用了first_number这个fixture,并且返回一个list
    return [first_number]
def test_secondnum1(order): #调用order,并且在order返回的list中添加 2 这个元素
    order.append(2)
    print(order)
    assert order==[1,2] #断言
def test_secondnum2(order): #也调用了order,并在order返回的list中添加 3 这个元素
    order.append(3)
    print(order)
    assert order==[1,3] #断言

运行结果:

上面这段代码我们声明了:
两个fixture——first_numberorder
first_number有一个返回值: 1
order调用了first_number,并返回一个列表: [1]

我们还定义了:
两个测试函数——test_secondnum1test_secondnum2,这两个测试函数都调用了order

test_secondnum1order的返回值做了一个append(2)的操作;test_secondnum1order的返回值做了一个append(3)的操作。

根据运行结果我们可以看出,两个测试函数对调用的fixture都做出了各自的操作,并且得到各自的一个运行结果。两者的运行结果没有因为都调用了order而相互产生影响。

fixture可被反复重用这一特点,对于确保测试之间彼此不受影响是非常有用的。我们可以声明一个通用的fixture函数,并使用这个特性来确保每个测试都能得到未受污染的测试数据,并且能从一个干净的初始状态开始执行。

2.2.3 测试函数/fixture函数可以一次调用多个fixture

文章前面我们有介绍过如何使用usefixtures来调用多个fixture,由此我们可以知道,pytest是允许测试函数和fixture函数按照自己的需求一次调用多个fixture的。

示例6:

演示代码:

import pytest

@pytest.fixture()
def first_number(): #第一个fixture,返回1
    return 1

@pytest.fixture()
def second_number(): #第二个fixture,返回2
    return 2

@pytest.fixture()
def third_number(): #第三个fixture,返回1
    return 3

@pytest.fixture()
def order(first_number,second_number): #调用first_number 和 second_number 返回 [1,2]
    return [first_number,second_number]

def test_case(order,third_number):  #调用order 和 third_number
    order.append(third_number)     #对 order做append的操作,将third_number的返回值加入list中
    print(order)
    assert order==[1,2,3]  #断言

运行结果:

演示代码中我们声明了:
四个fixture——first_numbersecond_numberthird_numberorder;
一个测试函数——test_case

order 调用了first_numbersecond_numbertest_case调用了orderthird_number。他们都根据自己的需求调用了多个fixture,并且正常被执行。

2.2.4 同一测试执行期间,fixture可被多次请求

其实在看官方文档的时候,我有点不太理解这部分的内容。当时看文字的描述感觉与“fixture能够被重复调用“这一点有冲突,但是通过官方文档的代码示例,我才明白这两点其实是不冲突的。

下面我们先看一下官方示例。

示例7:

演示代码:

import pytest

@pytest.fixture
def first_entry():
    return "a"

@pytest.fixture
def order():
    return []

@pytest.fixture
def append_first(order, first_entry):
    return order.append(first_entry)

def test_string_only(append_first,order, first_entry):
    print(order)
    assert order == [first_entry]

运行结果:

示例代码中声明了:
三个fixture函数——first_entryorderappend_first;
一个测试函数——test_string_only

first_entry返回了一个str: "a"
order返回一个空list:[]
append_first调用了first_entryorder,并且返回 order.append(first_entry)

test_string_only调用了first_entryorderappend_first,并做了一个打印order值的操作和断言操作。

通过运行结果我们可以看到,test_string_only断言成功,并且打印的order的值是['a']

如果按照”fixture能够被重复调用“这一特点看,打印的order不应该是空list的吗?为什么会是[‘a']呢?

test_string_only在执行期间,先执行append_first,而append_first调用了order,并且对order进行了添加元素的操作,更改了order的值,此时order返回的值会存在缓存中。当test_string_only后面再去”调用“order的时候,其实和append_first引用的是同一个order对象,因此测试断言才会成功。

通过pytest官方文档我们知道,pytest一次只缓存一个fixture的实例,这意味着在使用参数化fixture时,pytest可以在给定范围内多次调用一个fixture。

当测试过程中先调用的fixture对其他fixture有依赖关系的话,在调用这个fixture的时候它所依赖的fixture也会被调用。所以后面测试执行过程中,如果再次有请求到这些fixture的话,fixture就不会被再次执行,此时会直接从缓存中获取到之前fixture执行后返回的数据来使用。

“fixture能够被重复调用“——针对不同的测试过程,目的是为了保障每个测试执行时都是一个干净的环境。
“同一测试执行期间,fixture可被多次请求”——同一测试过程中,目的是为了保障在测试过程中,前后使用的数据不会被重置。

文末说明:
以上内容是我在阅读pytest官方文档后,依照个人理解进行整理。内容可能会有理解错误之处,欢迎大家留言指正。谢谢

以上就是pytest自动化测试中的fixture的声明和调用的详细内容,更多关于fixture声明和调用的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解Pytest测试用例的执行方法

    pytest概述 pytest是一个非常成熟的全功能的Python测试框架,主要特点有以下几点: 1.简单灵活,容易上手,文档丰富: 2.支持参数化,可以细粒度地控制要测试的测试用例: 3.能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试.接口自动化测试(pytest+requests); 4.pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium).pytest-html(完美html

  • Python pytest装饰器总结(实例详解)

    几个常用装饰器 pytest.ini 配置文件 例子: [pytest] addopts = -v -s --html=py_test/scripts/report/report.html -p no:warnings --reruns=10 testpaths = ./py_test/scripts python_files= test_rerun.py python_classes = Test* python_function = test* xfail_strict = true add

  • python pytest进阶之fixture详解

    前言 学pytest就不得不说fixture,fixture是pytest的精髓所在,就像unittest中的setup和teardown一样,如果不学fixture那么使用pytest和使用unittest是没什么区别的(个人理解). fixture用途 1.做测试前后的初始化设置,如测试数据准备,链接数据库,打开浏览器等这些操作都可以使用fixture来实现 2.测试用例的前置条件可以使用fixture实现 3.支持经典的xunit fixture ,像unittest使用的setup和te

  • python pytest进阶之conftest.py详解

    前言 前面几篇文章基本上已经了解了pytest 命令使用,收集用例,finxture使用及作用范围,今天简单介绍一下conftest.py文件的作用和实际项目中如是使用此文件! 实例场景 首先们思考这样一个问题:如果我们在编写测试用的时候,每一个测试文件里面的用例都需要先登录后才能完成后面的操作,那么们该如何实现呢?这就需要我们掌握conftest.py文件的使用了. 实例代码 创建如下一个目录 ConftestFile |conftest.py |test_file_01.py |test_f

  • pytest自动化测试中的fixture的声明和调用

    目录 1. fixture的声明 2. fixture的调用 2.1 fixture的调用方式 2.1.1 使用fixturename 2.1.2 使用@pytest.mark.usefixtures("fixturename") 2.1.3 autouse--自动应用 2.2 fixture使用的灵活性 2.2.1 一个fixture函数可以调用其他的fixture 2.2.2 fixture函数可被反复重用 2.2.3 测试函数/fixture函数可以一次调用多个fixture 2

  • pytest自动化测试fixture的作用域实例化顺序及可用性

    目录 1. fixture的作用域 1.1 scope 1.function: 2.class: 3.module: 4.package: 5.session: 1.2 动态作用域(Dynamic scope) 1.带参数-k运行 2.无参数-k运行 2. fixture的实例化顺序 2.1 作用域级别高的fixture先执行 2.2 fixture函数的依赖项先执行 2.3 自动使用的fixture在其作用域内首先执行 本节总结 3. fixture的可用性 1. fixture的作用域 1.

  • pytest中的fixture基本用法

    目录 简介: fixture的功能 特点及优势 基本用法 fixture在自动化中的应用--作用域 fixture在自动化中的应用-yield关键字 fixture在自动化中的应用--数据共享 fixture在自动化中的应用-自动应用 fixture在自动化中的应用-参数化 简介: fixture区别于unnitest的传统单元测试(setup/teardown)有显著改进: 1.有独立的命名,并通过声明它们从测试函数.模块.类或整个项目中的使用来激活. 2.按模块化的方式实现,每个fixtur

  • pytest进阶教程之fixture函数详解

    fixture函数存在意义 与python自带的unitest测试框架中的setup.teardown类似,pytest提供了fixture函数用以在测试执行前和执行后进行必要的准备和清理工作.但是相对来说又比setup.teardown好用. firture相对于setup和teardown的优势 命名方式灵活,不局限于setup和teardown这几个命名 conftest.py 配置里可以实现数据共享,不需要import就能自动找到一些配置 scope="module" 可以实现

  • python pytest进阶之xunit fixture详解

    前言 今天我们再说一下pytest框架和unittest框架相同的fixture的使用, 了解unittest的同学应该知道我们在初始化环境和销毁工作时,unittest使用的是setUp,tearDown方法,那么在pytest框架中同样存在类似的方法,今天我们就来具体说明. 先附上官方文档的一段说明 1.每个级别的setup/teardown都可以多次复用 2.如果相应的初始化函数执行失败或者被跳过则不会执行teardown方法 3.在pytest4.2之前,xunit fixture 不遵

  • Appium+Python+pytest自动化测试框架的实战

    菜鸟一枚,写的不好勿喷,大家一起学习 先简单介绍一下目录,再贴一些代码,代码里有注释 Basic目录下写的是一些公共的方法,Data目录下写的是测试数据,image存的是测试失败截图,Log日志文件,Page测试的定位元素,report测试报告,Test测试用例,pytest.ini是pytest启动配置文件,requirements.txt需要安装的py模块,run.py运行文件 Basic/base.py 里面封装了 一些方法,元素的点击,输入,查找,还有一些自己需要的公共方法也封装在里面,

  • pytest自动化测试数据驱动yaml/excel/csv/json

    目录 数据驱动 1.pytest结合数据驱动-yaml 工程目录结构: 2.pytest结合数据驱动-excel 工程目录结构: 3.pyetst结合数据驱动-csv 读取csv数据: 工程目录结构: 4.pytest结合数据驱动-json json结构: 查看json文件: 读取json文件: 工程目录结构: 数据驱动 数据的改变从而驱动自动化测试用例的执行,最终引起测试结果的改变.简单说就是参数化的应用. 测试驱动在自动化测试中的应用场景: 测试步骤的数据驱动: 测试数据的数据驱动: 配置的

  • 浅谈JavaScript中变量和函数声明的提升

    现象: 1. 在JavaScript中变量和函数的声明会提升到最顶部执行. 2. 函数的提升高于变量的提升. 3. 函数内部如果用var声明了相同名称的外部变量,函数将不再向上寻找. 4. 匿名函数不会提升. 5. 不同<script>块中的函数互不影响. 例子: 函数声明提升高于变量声明 //同时声明变量a和函数a var a; function a() {} alert(typeof a); //显示的是"function",初步证明function的优先级高于var.

  • Java自动化测试中多数据源的切换(实例讲解)

    在做自动化测试时,数据驱动是一个很重要的概念,当数据与脚本分离后,面对茫茫多的数据,管理数据又成了一个大问题,而数据源又可能面对多个,就跟在开发过程中,有时候要连接MYSQL,有时候又要连接SQL SERVER一样,如何做到快速切换?下面的示例中,我们将从一个数据源开始,一步步的演示下去: 一. 用外部文件做数据驱动的基本写法 1.1 我们在做数据驱动时,把数据存储在JAVA的属性文件中:data.properties username=test password=123456 1.2 解析pr

  • 详解js中let与var声明变量的区别

    ES6 新增了let命令,用来声明局部变量,所声明的变量,只在let命令所在的代码块内有效,而且有暂时性死区的约束. 1.ES6可以用let定义块级作用域变量 代码如下: function f1(){ { var a = 10; let b = 20; } console.log(a); // 10 console.log(b); // Uncaught ReferenceError: b is not defined } f1(); 说明:在ES6之前只有全局作用域和函数作用域,在ES6中新增

随机推荐