专栏首页橙子探索测试Python pytest框架之@pytest.fixture()和conftest详解

Python pytest框架之@pytest.fixture()和conftest详解

一、fixture简介 学pytest就不得不说fixture,fixture是pytest的精髓所在,类似unittest中setup/teardown这种前后置东西。但是比它们要强大、灵活很多,它的优势是可以跨文件共享 fixture的目的是提供一个固定基线,在该基线上测试可以可靠地和重复地执行。fixture提供了区别于传统单元测试(setup/teardown)有显著改进 1、有独立的命名,并通过声明它们从测试函数、模块、类或整个项目中的使用来激活。 2、按模块化的方式实现,每个fixture都可以互相调用。 3、fixture的范围从简单的单元扩展到复杂的功能测试,允许根据配置和组件选项对fixture和测试用例进行参数化,或者跨函数function、类class、模块module或整个测试会话sessio范围。

二、用途: 1.做测试前后的初始化设置,如测试数据准备,链接数据库,打开浏览器等这些操作都可以使用fixture来实现 2.测试用例的前置条件可以使用fixture实现 3.支持经典的xunit fixture ,像unittest使用的setup和teardown 4.fixture可以实现unittest不能实现的功能,比如unittest中的测试用例和测试用例之间是无法传递参数和数据的,但是fixture却可以解决这个问题

三、fixture作为参数传入: 1、定义fixture跟定义普通函数差不多,唯一区别就是在函数上加个装饰器@pytest.fixture(),fixture命名不要用test_开头,跟用例区分开。用例才是test_开头的命名。 2、fixture是可以有返回值的,如果没return默认返回None。用例调用fixture的返回值,直接就是把fixture的函数名称当成变量传入 3、fixture装饰器里的scope有四个级别的参数。“function(不写默认这个)”,“class”,“module”or“session” 4、除scope之外。还有params、autouse、ids、name等。 5、fixture可以有返回值,如果没有return,默认会是None;用例调用fixture的返回值,就是直接把fixture的函数名称作为参数传入

6、fixture可以返回一个元组、列表或字典

7、test_用例可传单个、多个fixture参数

8、fixture与fixture间可相互调用

fixture可以返回一个元组、列表或字典

@pytest.fixture()
def user():
    print("=====打印装饰器函数=====")
    username='wangli'
    psw=123456
    assert username=="wangli"
    assert psw == 123456
    return username,psw
def test_login(user):
    print(user)
    assert user[0]=="wangli"
    assert user[1] == 123456

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


"C:\Program Files\Python35\python.exe" C:/Users/wangli/PycharmProjects/test/test/test03.py
============================= test session starts =============================
platform win32 -- Python 3.5.2, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: C:\Users\wangli\PycharmProjects\test\test
collected 1 item

test03.py =====打印装饰器函数=====
('wangli', 123456)
.

============================== 1 passed in 0.16s ==============================

Process finished with exit code 0
test_用例可传单个、多个fixture参数

@pytest.fixture()
def username():
    print("=====打印username装饰器函数=====")
    username='wangli'
    assert username=="wangli"
    return username
@pytest.fixture()
def psw():
    print("=====打印psw装饰器函数=====")
    psw=123456
    assert psw==123456
    return psw
def test_login(username,psw):
    print(username,psw)
    assert username=="wangli"
    assert psw == 123456

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


"C:\Program Files\Python35\python.exe" C:/Users/wangli/PycharmProjects/test/test/test03.py
============================= test session starts =============================
platform win32 -- Python 3.5.2, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: C:\Users\wangli\PycharmProjects\test\test
collected 1 item

test03.py =====打印username装饰器函数=====
=====打印psw装饰器函数=====
wangli 123456
.

============================== 1 passed in 0.13s ==============================

Process finished with exit code 0
fixture与fixture间可相互调用

@pytest.fixture()
def first():
    print("=====first=====")
    username='wangli'
    assert username=="wangli"
    return username
@pytest.fixture()
def sencond(first):
    print("=====sencond=====")
    psw=123456
    assert psw==123456
    return first,psw
def test_login(sencond):
    print(sencond)
    assert sencond[0]=="wangli"
    assert sencond[1] == 123456

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


"C:\Program Files\Python35\python.exe" C:/Users/wangli/PycharmProjects/test/test/test03.py
============================= test session starts =============================
platform win32 -- Python 3.5.2, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: C:\Users\wangli\PycharmProjects\test\test
collected 1 item

test03.py =====first=====
=====sencond=====
('wangli', 123456)
.

============================== 1 passed in 0.02s ==============================

Process finished with exit code 0

四、fixture源码详解: fixture(scope='function',params=None,autouse=False,ids=None,name=None): fixture里面有个scope参数可以控制fixture的作用范围,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>')"。

五、fixture的作用范围

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

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

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

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

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

function默认模式@pytest.fixture(scope='function')或 @pytest.fixture()

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

class类级别@pytest.fixture(scope='class')

如果一个class里面有多个用例,都调用了1次fixture,那么此fixture只在此class里所有用例开始前执行一次

@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","test03.py"])

"C:\Program Files\Python35\python.exe" C:/Users/wangli/PycharmProjects/test/test/test03.py
============================= test session starts =============================
platform win32 -- Python 3.5.2, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: C:\Users\wangli\PycharmProjects\test\test
collected 2 items

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

============================== 2 passed in 0.09s ==============================

Process finished with exit code 0

module模块级别@pytest.fixture(scope='module')

每一个.py文件调用一次,fixture为module时,在当前.py脚本里面所有用例开始前只执行一次,模块里所有的用例执行前执行一次module级别的fixture

@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","test03.py"])

"C:\Program Files\Python35\python.exe" C:/Users/wangli/PycharmProjects/test/test/test03.py
============================= test session starts =============================
platform win32 -- Python 3.5.2, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: C:\Users\wangli\PycharmProjects\test\test
collected 2 items

test03.py 传出了男, 且在当前py文件下执行一次!!!
找到name
.找到sex
.

============================== 2 passed in 0.09s ==============================

Process finished with exit code 0

session 会话级别@pytest.fixture(scope='session')

1、可以跨.py文件调用,有多个.py文件调用时,实际只调用了一次fixture

2、conftest.py与运行的用例要在同一个pakage下,并且有__init__.py文件

3、不需要import导入 conftest.py,pytest会自动识别该文件,放到项目的根目录下就可以全局调用了,如果放到某个package下,那就在改package内有效

4、conftest.py配置脚本名称是固定的,不能改名称

多个.py文件只调用1次fixture

import pytest
# conftest.py
@pytest.fixture(scope='session')
def get_token():
    token = 'qeehfjejwjwjej11sss@22'
    print('获取到token:%s' % token)
    return token



import pytest
# test02.py
class Test(object):
    def test2(self,get_token):
        token = 'qeehfjejwjwjej11sss@22'
        print("【执行test02.py-Test类-test2用例,获取get_token:%s】" %get_token)
        assert get_token == token

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


import pytest
#test03.py
class Test(object):
    def test3(self,get_token):
        token = 'qeehfjejwjwjej11sss@22'
        print("【执行test03.py-Test类-test3用例,获取get_token:%s】" %get_token)
        assert get_token == token
    def test4(self,get_token):
        token = 'qeehfjejwjwjej11sss@22'
        print("【执行test03.py-Test类-test4用例,获取get_token:%s】" %get_token)
        assert get_token == token

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



"C:\Program Files\Python35\python.exe" C:/Users/wangli/PycharmProjects/Test/test/test02.py
============================= test session starts =============================
platform win32 -- Python 3.5.2, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: C:\Users\wangli\PycharmProjects\Test\test
collected 3 items

test02.py 获取到token:qeehfjejwjwjej11sss@22
【执行test02.py-Test类-test2用例,获取get_token:qeehfjejwjwjej11sss@22】
.
test03.py 【执行test03.py-Test类-test3用例,获取get_token:qeehfjejwjwjej11sss@22】
.【执行test03.py-Test类-test4用例,获取get_token:qeehfjejwjwjej11sss@22】
.

============================== 3 passed in 0.30s ==============================

Process finished with exit code 0









多个.py文件只调用多次fixture

import pytest
# conftest.py
@pytest.fixture()
def get_token():
    token = 'qeehfjejwjwjej11sss@22'
    print('获取到token:%s' % token)
    return token



import pytest
# test02.py
class Test(object):
    def test2(self,get_token):
        token = 'qeehfjejwjwjej11sss@22'
        print("【执行test02.py-Test类-test2用例,获取get_token:%s】" %get_token)
        assert get_token == token

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


import pytest
#test03.py
class Test(object):
    def test3(self,get_token):
        token = 'qeehfjejwjwjej11sss@22'
        print("【执行test03.py-Test类-test3用例,获取get_token:%s】" %get_token)
        assert get_token == token
    def test4(self,get_token):
        token = 'qeehfjejwjwjej11sss@22'
        print("【执行test03.py-Test类-test4用例,获取get_token:%s】" %get_token)
        assert get_token == token

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



"C:\Program Files\Python35\python.exe" C:/Users/wangli/PycharmProjects/Test/test/test03.py
============================= test session starts =============================
platform win32 -- Python 3.5.2, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: C:\Users\wangli\PycharmProjects\Test\test
collected 3 items

test02.py 获取到token:qeehfjejwjwjej11sss@22
【执行test02.py-Test类-test2用例,获取get_token:qeehfjejwjwjej11sss@22】
.
test03.py 获取到token:qeehfjejwjwjej11sss@22
【执行test03.py-Test类-test3用例,获取get_token:qeehfjejwjwjej11sss@22】
.获取到token:qeehfjejwjwjej11sss@22
【执行test03.py-Test类-test4用例,获取get_token:qeehfjejwjwjej11sss@22】
.

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

Process finished with exit code 0

本文分享自微信公众号 - 橙子探索测试(chengzitest)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Windows 下 python 版本切换

    编最近在学习python相关的知识,电脑中安装的是python3,就发现一些python2脚本无法顺利运行。

    一名白帽的成长史
  • 谷歌重磅发布TensorFlow 2.0正式版,高度集成Keras,大量性能改进

    TensorFlow 2.0 安装指南:https://www.tensorflow.org/install

    机器之心
  • Flink 数据类型 以及 第一阶段小结

    在 Flink 中,数据类型的描述信息都是定义在 TypeInformation 中,比较常用的 TypeInformatica 有 BasicTypeInfo...

    kk大数据
  • CuPy | 教你一招将Numpy加速700倍?

    就其自身来说,Numpy 的速度已经较 Python 有了很大的提升。当你发现 Python 代码运行较慢,尤其出现大量的 for-loops 循环时,通常可以...

    昱良
  • GitHub万星NLP资源大升级:实现Pytorch和TF深度互操作,集成32个最新预训练模型

    刚刚, 抱抱脸(Hugging Face)团队,放出了transformers 2.0版本。

    代码医生工作室
  • 12.Django基础十之Form和ModelForm组件

      我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。

    changxin7
  • 17个Python骚操作,你都Ok吗?

    Python 是一门非常优美的语言,其简洁易用令人不得不感概人生苦短。在本文中,作者 Gautham Santhosh 带我们回顾了 17 个非常有用的 Pyt...

    小小詹同学
  • python实现pdf文档合并

    之前一番在免费知识星球给大家开发过一个在windows下使用的简单的pdf合并工具。其实用python去实现真的很简单,用了tkinter + PyPDF2 +...

    efonfighting
  • pyspider最佳实践

    pyspider是好东西,非常稳定,很久很久以前架了一个,心冷了一段时间,但人家尽忠职守地持续运行,一直在抓取东西。

    用户1075292
  • 盘一盘 Python 系列特别篇 - 面向对象编程

    在写 Keras (下) 时,发现很多内容都要用到类 (class) 和对象 (object),因此本文作为 Python 系列的特别篇,主要介绍面向对象编程 ...

    用户5753894

扫码关注云+社区

领取腾讯云代金券