pytest框架之fixture详细使用详解

本人之前写了一套基于unnitest框架的UI自动化框架,但是发现了pytest框架之后觉得unnitest太low,现在重头开始学pytest框架,一边学习一边记录,和大家分享,话不多说,那就先从pytest框架的精髓fixture说起吧!

简介:

  fixture区别于unnitest的传统单元测试(setup/teardown)有显著改进:

  1.有独立的命名,并通过声明它们从测试函数、模块、类或整个项目中的使用来激活。

  2.按模块化的方式实现,每个fixture都可以互相调用。

  3.fixture的范围从简单的单元测试到复杂的功能测试,可以对fixture配置参数,或者跨函数function,类class,模块module或整个测试session范围。

(很重要!!!)(很重要!!!)(很重要!!!)

谨记:当我们使用pytest框架写case的时候,一定要拿它的命令规范去case,这样框架才能识别到哪些case需要执行,哪些不需要执行。

用例设计原则

文件名以test_*.py文件和*_test.py

以test_开头的函数

以Test开头的类

以test_开头的方法

fixture可以当做参数传入

定义fixture跟定义普通函数差不多,唯一区别就是在函数上加个装饰器@pytest.fixture(),fixture命名不要以test开头,跟用例区分开。fixture是有返回值得,没有返回值默认为None。用例调用fixture的返回值,直接就是把fixture的函数名称当做变量名称。

ex:

import pytest

@pytest.fixture()
def test1():
    a = 'leo'
    return a

def test2(test1):
    assert test1 == 'leo'

if __name__ == '__main__':
    pytest.main('-q test_fixture.py')

输出:

============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 1 item

test_fixture.py .                                                        [100%]

========================== 1 passed in 0.02 seconds ===========================
Process finished with exit code 0

使用多个fixture

如果用例需要用到多个fixture的返回数据,fixture也可以返回一个元祖,list或字典,然后从里面取出对应数据。

ex:

import pytest

@pytest.fixture()
def test1():
    a = 'leo'
    b = '123456'
    print('传出a,b')
    return (a, b)

def test2(test1):
    u = test1[0]
    p = test1[1]
    assert u == 'leo'
    assert p == '123456'
    print('元祖形式正确')

if __name__ == '__main__':
    pytest.main('-q test_fixture.py')

输出结果:
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 1 item

test_fixture.py 传出a,b
.元祖形式正确
                                                        [100%]

========================== 1 passed in 0.02 seconds ===========================
Process finished with exit code 0

当然也可以分成多个fixture,然后在用例中传多个fixture参数

import pytest

@pytest.fixture()
def test1():
    a = 'leo'
    print('\n传出a')
    return a

@pytest.fixture()
def test2():
    b = '123456'
    print('传出b')
    return b

def test3(test1, test2):
    u = test1
    p = test2
    assert u == 'leo'
    assert p == '123456'
    print('传入多个fixture参数正确')

if __name__ == '__main__':
    pytest.main('-q test_fixture.py')

输出结果:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 1 item

test_fixture.py
传出a
传出b
.传入多个fixture参数正确

fixture互相调用

import pytest

@pytest.fixture()
def test1():
    a = 'leo'
    print('\n传出a')
    return a

def test2(test1):
    assert test1 == 'leo'
    print('fixture传参成功')

if __name__ == '__main__':
    pytest.main('-q test_fixture.py')

输出结果:
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 1 item

test_fixture.py
传出a
.fixture传参成功
                                                        [100%]

========================== 1 passed in 0.03 seconds ===========================
Process finished with exit code 0

介绍完了fixture的使用方式,现在介绍一下fixture的作用范围(scope)

fixture的作用范围

fixture里面有个scope参数可以控制fixture的作用范围:session>module>class>function

-function:每一个函数或方法都会调用

-class:每一个类调用一次,一个类中可以有多个方法

-module:每一个.py文件调用一次,该文件内又有多个function和class

-session:是多个文件调用一次,可以跨.py文件调用,每个.py文件就是module

fixture源码详解

fixture(scope='function',params=None,autouse=False,ids=None,name=None):

scope:有四个级别参数"function"(默认),"class","module","session"

params:一个可选的参数列表,它将导致多个参数调用fixture功能和所有测试使用它。

autouse:如果True,则为所有测试激活fixture func可以看到它。如果为False则显示需要参考来激活fixture

ids:每个字符串id的列表,每个字符串对应于params这样他们就是测试ID的一部分。如果没有提供ID它们将从params自动生成

name:fixture的名称。这默认为装饰函数的名称。如果fixture在定义它的统一模块中使用,夹具的功能名称将被请求夹具的功能arg遮蔽,解决这个问题的一种方法时将装饰函数命令"fixture_<fixturename>"然后使用"@pytest.fixture(name='<fixturename>')"。

具体阐述一下scope四个参数的范围

scope="function"

@pytest.fixture()如果不写参数,参数就是scope="function",它的作用范围是每个测试用例来之前运行一次,销毁代码在测试用例之后运行。

import pytest

@pytest.fixture()
def test1():
    a = 'leo'
    print('\n传出a')
    return a

@pytest.fixture(scope='function')
def test2():
    b = '男'
    print('\n传出b')
    return b

def test3(test1):
    name = 'leo'
    print('找到name')
    assert test1 == name

def test4(test2):
    sex = '男'
    print('找到sex')
    assert test2 == sex

if __name__ == '__main__':
    pytest.main('-q test_fixture.py')

输出结果:

platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 2 items

test_fixture.py
传出a
.找到name

传出b
.找到sex
                                                       [100%]

========================== 2 passed in 0.04 seconds ===========================

放在类中实现结果也是一样的

import pytest

@pytest.fixture()
def test1():
    a = 'leo'
    print('\n传出a')
    return a

@pytest.fixture(scope='function')
def test2():
    b = '男'
    print('\n传出b')
    return b

class TestCase:
    def test3(self, test1):
        name = 'leo'
        print('找到name')
        assert test1 == name

    def test4(self, test2):
        sex = '男'
        print('找到sex')
        assert test2 == sex

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

输出结果:

platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 2 items

test_fixture.py
传出a
.找到name

传出b
.找到sex
                                                       [100%]

========================== 2 passed in 0.03 seconds ===========================
Process finished with exit code 0

scope="class"

fixture为class级别的时候,如果一个class里面有多个用例,都调用了次fixture,那么此fixture只在此class里所有用例开始前执行一次。

import pytest

@pytest.fixture(scope='class')
def test1():
    b = '男'
    print('传出了%s, 且只在class里所有用例开始前执行一次!!!' % b)
    return b

class TestCase:
    def test3(self, test1):
        name = '男'
        print('找到name')
        assert test1 == name

    def test4(self, test1):
        sex = '男'
        print('找到sex')
        assert test1 == sex

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

输出结果:
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 2 items

test_fixture.py 传出了男, 且只在class里所有用例开始前执行一次!!!
.找到name
.找到sex
                                                       [100%]

========================== 2 passed in 0.05 seconds ===========================
Process finished with exit code 0

scope="module"

fixture为module时,在当前.py脚本里面所有用例开始前只执行一次。

import pytest
##test_fixture.py

@pytest.fixture(scope='module')
def test1():
    b = '男'
    print('传出了%s, 且在当前py文件下执行一次!!!' % b)
    return b

def test3(test1):
    name = '男'
    print('找到name')
    assert test1 == name

class TestCase:

    def test4(self, test1):
        sex = '男'
        print('找到sex')
        assert test1 == sex

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

输出结果:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 2 items

test_fixture.py 传出了男, 且在当前py文件下执行一次!!!
.找到sex
.找到name
                                                       [100%]

========================== 2 passed in 0.03 seconds ===========================
Process finished with exit code 0

scope="session"

fixture为session级别是可以跨.py模块调用的,也就是当我们有多个.py文件的用例的时候,如果多个用例只需调用一次fixture,那就可以设置为scope="session",并且写到conftest.py文件里。

conftest.py文件名称时固定的,pytest会自动识别该文件。放到项目的根目录下就可以全局调用了,如果放到某个package下,那就在改package内有效。

文件目录为

import pytest
# conftest.py

@pytest.fixture(scope='session')
def test1():
    sex = '男'
    print('获取到%s' % sex)
    return sex
import pytest
# test_fixture.py

def test3(test1):
    name = '男'
    print('找到name')
    assert test1 == name

if __name__ == '__main__':
    pytest.main(['-s', 'test_fixture.py'])
import pytest
# test_fixture1.py

class TestCase:

    def test4(self, test1):
        sex = '男'
        print('找到sex')
        assert test1 == sex

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

如果需要同时执行两个py文件,可以在cmd中在文件py文件所在目录下执行命令:pytest -s test_fixture.py test_fixture1.py

执行结果为:

================================================= test session starts =================================================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:
collected 2 items

test_fixture.py 获取到男
找到name
.
test_fixture1.py 找到sex
.

============================================== 2 passed in 0.05 seconds ===============================================

调用fixture的三种方法

1.函数或类里面方法直接传fixture的函数参数名称

import pytest
# test_fixture1.py

@pytest.fixture()
def test1():
    print('\n开始执行function')

def test_a(test1):
    print('---用例a执行---')

class TestCase:

    def test_b(self, test1):
        print('---用例b执行')

输出结果:
test_fixture1.py
开始执行function
.---用例a执行---

开始执行function
.---用例b执行
                                                      [100%]

========================== 2 passed in 0.05 seconds ===========================
Process finished with exit code 0

2.使用装饰器@pytest.mark.usefixtures()修饰需要运行的用例

import pytest
# test_fixture1.py

@pytest.fixture()
def test1():
    print('\n开始执行function')

@pytest.mark.usefixtures('test1')
def test_a():
    print('---用例a执行---')

@pytest.mark.usefixtures('test1')
class TestCase:

    def test_b(self):
        print('---用例b执行---')

    def test_c(self):
        print('---用例c执行---')

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

输出结果:
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 3 items

test_fixture1.py
开始执行function
.---用例a执行---

开始执行function
.---用例b执行---

开始执行function
.---用例c执行---
                                                     [100%]

========================== 3 passed in 0.06 seconds ===========================
Process finished with exit code 0

叠加usefixtures

如果一个方法或者一个class用例想要同时调用多个fixture,可以使用@pytest.mark.usefixture()进行叠加。注意叠加顺序,先执行的放底层,后执行的放上层。

import pytest
# test_fixture1.py

@pytest.fixture()
def test1():
    print('\n开始执行function1')

@pytest.fixture()
def test2():
    print('\n开始执行function2')

@pytest.mark.usefixtures('test1')
@pytest.mark.usefixtures('test2')
def test_a():
    print('---用例a执行---')

@pytest.mark.usefixtures('test2')
@pytest.mark.usefixtures('test1')
class TestCase:

    def test_b(self):
        print('---用例b执行---')

    def test_c(self):
        print('---用例c执行---')

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

输出结果:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 3 items

test_fixture1.py
开始执行function2

开始执行function1
.---用例a执行---

开始执行function1

开始执行function2
.---用例b执行---

开始执行function1

开始执行function2
.---用例c执行---
                                                     [100%]

========================== 3 passed in 0.03 seconds ===========================
Process finished with exit code 0

usefixtures与传fixture区别

如果fixture有返回值,那么usefixture就无法获取到返回值,这个是装饰器usefixture与用例直接传fixture参数的区别。

当fixture需要用到return出来的参数时,只能讲参数名称直接当参数传入,不需要用到return出来的参数时,两种方式都可以。

fixture自动使用autouse=True

当用例很多的时候,每次都传这个参数,会很麻烦。fixture里面有个参数autouse,默认是False没开启的,可以设置为True开启自动使用fixture功能,这样用例就不用每次都去传参了

autouse设置为True,自动调用fixture功能

import pytest
# test_fixture1.py

@pytest.fixture(scope='module', autouse=True)
def test1():
    print('\n开始执行module')

@pytest.fixture(scope='class', autouse=True)
def test2():
    print('\n开始执行class')

@pytest.fixture(scope='function', autouse=True)
def test3():
    print('\n开始执行function')

def test_a():
    print('---用例a执行---')

def test_d():
    print('---用例d执行---')

class TestCase:

    def test_b(self):
        print('---用例b执行---')

    def test_c(self):
        print('---用例c执行---')

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

输出结果:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 4 items

test_fixture1.py
开始执行module

开始执行class

开始执行function
.---用例a执行---

开始执行class

开始执行function
.---用例d执行---

开始执行class

开始执行function
.---用例b执行---

开始执行function
.---用例c执行---
                                                    [100%]

conftest.py的作用范围

一个工程下可以建多个conftest.py的文件,一般在工程根目录下设置的conftest文件起到全局作用。在不同子目录下也可以放conftest.py的文件,作用范围只能在改层级以及以下目录生效。

项目实例:

目录结构:

1.conftest在不同的层级间的作用域不一样

# conftest层级展示/conftest.py

import pytest

@pytest.fixture(scope='session', autouse=True)
def login():
    print('----准备登录----')

# conftest层级展示/sougou_login/conftest
import pytest

@pytest.fixture(scope='session', autouse=True)
def bai_du():
    print('-----登录百度页面-----')

# conftest层级展示/sougou_login/login_website
import pytest

class TestCase:
    def test_login(self):
        print('hhh,成功登录百度')

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

输出结果:

============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\conftest层级演示\sougou_login, inifile:collected 1 item

login_website.py ----准备登录----
-----登录百度页面-----
.hhh,成功登录百度
                                                       [100%]

========================== 1 passed in 0.03 seconds ===========================
Process finished with exit code 0

2.conftest是不能跨模块调用的(这里没有使用模块调用)

# conftest层级演示/log/contfest.py
import pytest

@pytest.fixture(scope='function', autouse=True)
def log_web():
    print('打印页面日志成功')

# conftest层级演示/log/log_website.py
import pytest

def test_web():
    print('hhh,成功一次打印日志')

def test_web1():
    print('hhh,成功两次打印日志')

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

输出结果:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\conftest层级演示\log, inifile:
collected 2 items

log_website.py ----准备登录----
打印页面日志成功
hhh,成功一次打印日志
.打印页面日志成功
hhh,成功两次打印日志
.

========================== 2 passed in 0.02 seconds ===========================

到此这篇关于pytest框架之fixture详细使用详解的文章就介绍到这了,更多相关pytest fixture内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python pytest进阶之xunit fixture详解

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

  • python pytest进阶之fixture详解

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

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

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

  • Pytest框架之fixture的详细使用教程

    前言 前面一篇讲了setup.teardown可以实现在执行用例前或结束后加入一些操作,但这种都是针对整个脚本全局生效的 如果有以下场景:用例 1 需要先登录,用例 2 不需要登录,用例 3 需要先登录.很显然无法用 setup 和 teardown 来实现了fixture可以让我们自定义测试用例的前置条件 fixture优势 命名方式灵活,不局限于 setup 和teardown 这几个命名 conftest.py 配置里可以实现数据共享,不需要 import 就能自动找到fixture sc

  • pytest框架之fixture详细使用详解

    本人之前写了一套基于unnitest框架的UI自动化框架,但是发现了pytest框架之后觉得unnitest太low,现在重头开始学pytest框架,一边学习一边记录,和大家分享,话不多说,那就先从pytest框架的精髓fixture说起吧! 简介: fixture区别于unnitest的传统单元测试(setup/teardown)有显著改进: 1.有独立的命名,并通过声明它们从测试函数.模块.类或整个项目中的使用来激活. 2.按模块化的方式实现,每个fixture都可以互相调用. 3.fixt

  • python的pytest框架之命令行参数详解(上)

    前言 pytest是一款强大的python自动化测试工具,可以胜任各种类型或者级别的软件测试工作.pytest提供了丰富的功能,包括assert重写,第三方插件,以及其他测试工具无法比拟的fixture模型.pytest是一个软件测试框架,是一款命令行工具,可以自动找到测试用例执行,并且回报测试结果.有丰富的基础库,可以大幅度提高用户编写测试用例的效率.具备扩展性,用户可以自己编写插件,或者安装第三方提供的插件.可以很容易地与其他工具集成到一起使用.比如持续集成,web自动化测试等. 下面列举了

  • python的pytest框架之命令行参数详解(下)

    前言 上篇说到命令行执行测试用例的部分参数如何使用?今天将继续更新其他一些命令选项的使用,和pytest收集测试用例的规则! pytest执行用例命令行参数 --collect-only:罗列出所有当前目录下所有的测试模块,测试类及测试函数 --tb=style:屏蔽测试用例执行输出的回溯信息,可以简化用例失败时的输出信息.style可以是 on,line,short,具体区别请自行体验 --lf:当一次用例执行完成后,如果其中存在失败的测试用例,那么我们可以使用此命令重新运行失败的测试用例 我

  • Pytest框架之fixture详解(三)

    本文关于fixture的内容如下: 1.参数化fixture 2.fixture工厂 3.request这个fixture 1.参数化fixture fixture有个params参数,允许我们传递数据. 语法格式: # conftest.py文件 ​ # fixture的params参数 # 取value1时,会把依赖此fixture的用例执行一遍. # 取value2时,会把依赖此fixture的用例执行一遍. # 取value3时,会把依赖此fixture的用例执行一遍. # params

  • Pytest框架之fixture详解(二)

    本文关于 fixture 的内容如下: fixture 的 autouse 参数 session 和 module 级别的 fixture 1.fixture 的 autouse 参数 pytest 当中的 fixture, 默认情况下在定义好之后,需要测试用例/测试类主动请求使用,才会执行. 但是它有一个参数叫做 autouse,默认是 False. 关闭 fixture 的自动调用/自动执行功能. 如果设置 autouse=True,则表示这个 fixture 在它的作用域范围内都会自动化执

  • Pytest框架之fixture详解(一)

    我们在编写测试用例,都会涉及到用例执行之前的环境准备工作,和用例执行之后的环境清理工作. 代码版的测试用例也不例外.在自动化测试框架当中,我们也需要编写: 用例执行之前的环境准备工作代码(前置工作代码) 用例执行之后的环境清理工作(后置工作代码) 通常,在自动化测试框架当中,都叫做fixture. pytest作为python语言的测试框架,它的fixture有2种实现方式. 一种是xunit-style,跟unittest框架的机制非常相似,即setup/teardown系列 一种是它自己的f

  • Pytest实现setup和teardown的详细使用详解

    前言 用过unittest的童鞋都知道,有两个前置方法,两个后置方法:分别是 setup() setupClass() teardown() teardownClass() Pytest也贴心的提供了类似setup.teardown的方法,并且还超过四个,一共有十种 模块级别:setup_module.teardown_module 函数级别:setup_function.teardown_function,不在类中的方法 类级别:setup_class.teardown_class 方法级别:

  • python框架flask表单实现详解

    这篇文章主要介绍了python框架flask表单实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 表单 表单用于注册,修改用户数据等场景. flask-wtf提供了一个包,可以创建表单:pip install flask-wtf 为了防止跨域请求,flask_wtf自己生成一个秘钥,用秘钥生成加密口令,然后用口令验证表单中的数据真伪(是否被篡改过) from flask import Flask from flask import req

  • Spring框架学习之Cache抽象详解

    目录 1.简介 cache和buffer 2.缓存抽象 3.spring缓存抽象与多进程 官方文档  8.0 Spring为不同缓存做了一层抽象,这里通过阅读文档以及源码会对使用以及原理做一些学习笔记. 1.简介 从3.1版开始,Spring Framework提供了对现有Spring应用程序透明地添加缓存的支持. 与事务支持类似,缓存抽象允许一致地使用各种缓存解决方案,而对代码的影响最小. 从Spring 4.1开始,通过JSR-107注释和更多自定义选项的支持,缓存抽象得到了显着改进. ca

随机推荐