pytest高级进阶之Fixture

一. fixture介绍

fixture是pytest的一个闪光点,pytest要精通怎么能不学习fixture呢?跟着我一起深入学习fixture吧。其实unittest和nose都支持fixture,但是pytest做得更炫。

fixture是pytest特有的功能,它用pytest.fixture标识,定义在函数前面。在你编写测试函数的时候,你可以将此函数名称做为传入参数,pytest将会以依赖注入方式,将该函数的返回值作为测试函数的传入参数。

fixture有明确的名字,在其他函数,模块,类或整个工程调用它时会被激活。

fixture是基于模块来执行的,每个fixture的名字就可以触发一个fixture的函数,它自身也可以调用其他的fixture。

我们可以把fixture看做是资源,在你的测试用例执行之前需要去配置这些资源,执行完后需要去释放资源。比如module类型的fixture,适合于那些许多测试用例都只需要执行一次的操作。

fixture还提供了参数化功能,根据配置和不同组件来选择不同的参数。

fixture主要的目的是为了提供一种可靠和可重复性的手段去运行那些最基本的测试内容。比如在测试网站的功能时,每个测试用例都要登录和退出,利用fixture就可以只做一次,否则每个测试用例都要做这两步也是冗余。

下面会反复提高Python的Module概念,Python中的一个Module对应的就是一个.py文件。其中定义的所有函数或者是变量都属于这个Module。这个Module 对于所有函数而言就相当于一个全局的命名空间,而每个函数又都有自己局部的命名空间。

二. Fixture基础实例入门

把一个函数定义为Fixture很简单,只能在函数声明之前加上“@pytest.fixture”。其他函数要来调用这个Fixture,只用把它当做一个输入的参数即可。

test_fixture_basic.py

importpytest@pytest.fixture()defbefore():print'\nbefore each test'deftest_1(before):print'test_1()'deftest_2(before):print'test_2()'assert0

下面是运行结果,test_1和test_2运行之前都调用了before,也就是before执行了两次。默认情况下,fixture是每个测试用例如果调用了该fixture就会执行一次的。

C:\Users\yatyang\PycharmProjects\pytest_example>pytest-v-s test_fixture_basic.py=============================test session starts=============================platform win32--Python2.7.13,pytest-3.0.6,py-1.4.32,pluggy-0.4.0--C:\Python27\python.execachedir:.cachemetadata:{'Python':'2.7.13','Platform':'Windows-7-6.1.7601-SP1','Packages':{'py':'1.4.32','pytest':'3.0.6','pluggy':'0.4.0'},'JAVA_HOME':'C:\\ProgramFiles(x86)\\Java\\jdk1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}rootdir:C:\Users\yatyang\PycharmProjects\pytest_example,inifile:plugins:metadata-1.3.0,html-1.14.2collected2items test_fixture_basic.py::test_1beforeeachtesttest_1()PASSEDtest_fixture_basic.py::test_2beforeeachtesttest_2()FAILED==================================FAILURES===================================___________________________________ test_2 ____________________________________before=Nonedeftest_2(before):print'test_2()'>assert0Eassert0test_fixture_basic.py:12:AssertionError=====================1failed,1passedin0.23seconds======================

如果你的程序出现了下面的错误,就是开始忘记添加‘import pytest',所以不要忘记罗。

===================================ERRORS====================================_________________ERRORcollecting test_fixture_decorator.py __________________test_fixture_decorator.py:2:in<module>@pytest.fixture()ENameError:name'pytest'isnotdefined!!!!!!!!!!!!!!!!!!!Interrupted:1errors during collection!!!!!!!!!!!!!!!!!!!===========================1errorin0.36seconds===========================

三. 调用fixture的三种方式

1. 在测试用例中直接调用它,例如第二部分的基础实例。

2. 用fixture decorator调用fixture

可以用以下三种不同的方式来写,我只变化了函数名字和类名字,内容没有变。第一种是每个函数前声明,第二种是封装在类里,类里的每个成员函数声明,第三种是封装在类里在前声明。在可以看到3中不同方式的运行结果都是一样。

test_fixture_decorator.py

import pytest@pytest.fixture()defbefore():print('\nbefore each test')@pytest.mark.usefixtures("before")deftest_1():print('test_1()')@pytest.mark.usefixtures("before")deftest_2():print('test_2()')classTest1:@pytest.mark.usefixtures("before")deftest_3(self):print('test_1()')@pytest.mark.usefixtures("before")deftest_4(self):print('test_2()')@pytest.mark.usefixtures("before")classTest2:deftest_5(self):print('test_1()')deftest_6(self):print('test_2()')

运行结果如下,和上面的基础实例的运行效果一样。

C:\Users\yatyang\PycharmProjects\pytest_example>pytest-v-s test_fixture_decorator.py=============================test session starts=============================platform win32--Python2.7.13,pytest-3.0.6,py-1.4.32,pluggy-0.4.0--C:\Python27\python.execachedir:.cachemetadata:{'Python':'2.7.13','Platform':'Windows-7-6.1.7601-SP1','Packages':{'py':'1.4.32','pytest':'3.0.6','pluggy':'0.4.0'},'JAVA_HOME':'C:\\Program Files (x86)\\Java\\jd

k1.7.0_01','Plugins':{'html':'1.14.2','metadata':'1.3.0'}}rootdir:C:\Users\yatyang\PycharmProjects\pytest_example,inifile:plugins:metadata-1.3.0,html-1.14.2collected6items test_fixture_decorator.py::test_1before each testtest_1()PASSEDtest_fixture_decorator.py::test_2before each testtest_2()PASSEDtest_fixture_decorator.py::Test1::test_3before each testtest_1()PASSEDtest_fixture_decorator.py::Test1::test_4before each testtest_2()PASSEDtest_fixture_decorator.py::Test2::test_5before each testtest_1()PASSEDtest_fixture_decorator.py::Test2::test_6before each testtest_2()PASSED==========================6passed in0.10seconds===========================

3. 用autos调用fixture

fixture decorator一个optional的参数是autouse, 默认设置为False。

当默认为False,就可以选择用上面两种方式来试用fixture。

当设置为True时,在一个session内的所有的test都会自动调用这个fixture。

权限大,责任也大,所以用该功能时也要谨慎小心。

importtimeimportpytest@pytest.fixture(scope="module",autouse=True)defmod_header(request):print('\n-----------------')print('module      : %s'%request.module.__name__)print('-----------------')@pytest.fixture(scope="function",autouse=True)deffunc_header(request):print('\n-----------------')print('function    : %s'%request.function.__name__)print('time        : %s'%time.asctime())print('-----------------')deftest_one():print('in test_one()')deftest_two():print('in test_two()')

从下面的运行结果,可以看到mod_header在该module内运行了一次,而func_header对于每个test都运行了一次,总共两次。该方式如果用得好,还是可以使代码更为简洁。

但是对于不熟悉自己组的测试框架的人来说,在pytest里面去新写测试用例,需要去了解是否已有一些fixture是module或者class级别的需要注意。

C:\Users\yatyang\PycharmProjects\pytest_example>pytest-v-s test_fixture_auto.py=============================test session starts=============================platform win32--Python2.7.13,pytest-3.0.6,py-1.4.32,pluggy-0.4.0--C:\Python27\python.execachedir:.cachemetadata:{'Python':'2.7.13','Platform':'Windows-7-6.1.7601-SP1','Packages':{'py':'1.4.32','pytest':'3.0.6','pluggy':'0.4.0'},'JAVA_HOME':'C:\\Program Files (x86)\\Java\\jd

k1.7.0_01','Plugins':{'html':'1.14.2','metadata':'1.3.0'}}rootdir:C:\Users\yatyang\PycharmProjects\pytest_example,inifile:plugins:metadata-1.3.0,html-1.14.2collected2items test_fixture_auto.py::test_one-----------------module:test_fixture_auto----------------------------------function:test_onetime:Sat Mar1806:56:542017-----------------intest_one()PASSEDtest_fixture_auto.py::test_two-----------------function:test_twotime:Sat Mar1806:56:542017-----------------intest_two()PASSED==========================2passed in0.03seconds===========================

四. fixture scope

function:每个test都运行,默认是function的scope

class:每个class的所有test只运行一次

module:每个module的所有test只运行一次

session:每个session只运行一次

比如你的所有test都需要连接同一个数据库,那可以设置为module,只需要连接一次数据库,对于module内的所有test,这样可以极大的提高运行效率。

五. fixture 返回值

在上面的例子中,fixture返回值都是默认None,我们可以选择让fixture返回我们需要的东西。如果你的fixture需要配置一些数据,读个文件,或者连接一个数据库,那么你可以让fixture返回这些数据或资源。

如何带参数

fixture还可以带参数,可以把参数赋值给params,默认是None。对于param里面的每个值,fixture都会去调用执行一次,就像执行for循环一样把params里的值遍历一次。

test_fixture_param.py

importpytest@pytest.fixture(params=[1,2,3])deftest_data(request):returnrequest.paramdeftest_not_2(test_data):print('test_data: %s'%test_data)asserttest_data!=2

可以看到test_not_2里面把用test_data里面定义的3个参数运行里三次。

C:\Users\yatyang\PycharmProjects\pytest_example>pytest-v-s test_fixture_param.py=============================test session starts=============================platform win32--Python2.7.13,pytest-3.0.6,py-1.4.32,pluggy-0.4.0--C:\Python27\python.execachedir:.cachemetadata:{'Python':'2.7.13','Platform':'Windows-7-6.1.7601-SP1','Packages':{'py':'1.4.32','pytest':'3.0.6','pluggy':'0.4.0'},'JAVA_HOME':'C:\\ProgramFiles(x86)\\Java\\jdk1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}rootdir:C:\Users\yatyang\PycharmProjects\pytest_example,inifile:plugins:metadata-1.3.0,html-1.14.2collected3items test_fixture_param.py::test_not_2[1]test_data:1PASSEDtest_fixture_param.py::test_not_2[2]test_data:2FAILEDtest_fixture_param.py::test_not_2[3]test_data:3PASSED==================================FAILURES===================================________________________________ test_not_2[2]________________________________test_data=2deftest_not_2(test_data):print('test_data: %s'%test_data)>assert test_data!=2Eassert2!=2test_fixture_param.py:9:AssertionError=====================1failed,2passedin0.24seconds======================

本文对pytest的fixture进行了深入的讲解和练习,希望读者能够把fixture这些高级功能都用到平时的pytest功能中,提高运行效率。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容