小门板儿

Menu

pytest夹具:fixture详解01

一、定义

pytest框架的fixture测试夹具就相当于unittest框架的setup、teardown,但相对之下它的功能更加强大和灵活。

1、命名方式灵活,不限于unittest的setup、teardown

2、可以实现数据共享,多个模块跨文件共享前置后置

3、可以实现多个模块跨文件使用一个session来完成多个用例

4、可以实现unittest不能实现的功能,比如unittest中的测试用例和测试用例之间是无法传递参数和数据的,但是fixture却可以解决这个问题

二、fixture调用

使用@pytest.fixture()用于声明函数是处理前置后置的测试夹具函数,

方式一:将fixture名称作为参数传给测试用例,可以传多个fixture,按先后顺序执行

方式二:装饰器:@pytest.mark.usefixtures(fixture_name)

1、使用在类上,代表这个类所有测试用例都会调用这个fixture

2、在用例上,代表只有这个用例调用这个fixture

3、可以使用多个fixture,按先后顺序执行

4、如果fixture有返回值,用这个装饰器是无法获取到返回值的,也就无法给用例传递数据,只能用方法一

方式三:fixture设置autouse=True自动调用,同样fixture有返回值时,无法获取返回值

import pytest
​
@pytest.fixture()
def fixture_a():
    print("this is my fixture")
​
#plan 1
​
def test_plan_a(fixture_a):
    print("this is plan a")
    print("haaaaaaaaaa")
​
#plan 2
@pytest.mark.usefixtures("fixture_a")
def test_plan_b():
    print("this is plan b")
    print("haaaaaaaaaa")
 输出结果:
rootdir: D:\pytest\learn01, configfile: pytest.ini
collected 2 items                                                                   
test_sample.py this is my fixture
this is plan a
haaaaaaaaaa
.this is my fixture
this is plan b
haaaaaaaaaa
#plan 3


@pytest.fixture(autouse=True)
def fixture_a():
    print("this is my fixture")


def test_plan_3():
    print("this is plan c")
    print("haaaaaaaaaa")
​
# 应用到类中
class TestClass:
    def test_plan_d(self):
        print("this is plan d")
        print("haaaaaaaaaa")
​
    def test_plan_e(self):
        print("this is plan e")
        print("haaaaaaaaaa")
 输出结果:
 test_sample.py this is my fixture
this is plan c
haaaaaaaaaa
.this is my fixture
this is plan d
haaaaaaaaaa
.this is my fixture
this is plan e
haaaaaaaaaa

三、fixture作用域

代码:@pytest.fixture(scope='作用范围'),参数如下:

优先级:session > package > module > class > function,优先级高的会在低的fixture之前先实例化(在function范围,最先调用的一定是autouse)

import pytest,time
@pytest.fixture(scope='class')
def my_fixture():
    print('前置条件,初始化列表')
    l=[]
    l.append(time.time)
    yield l
    print('后置条件,清空列表')
    l=[]
​
class TestCase:
    def test_case01(self,my_fixture):
        l=my_fixture
        print('first case')
        print('列表长度为:')
        print(len(l))
        assert 1==1
​
    def test_case02(self,my_fixture):
        l=my_fixture
        print('second case')
        print('列表长度为:')
        print(len(l))
        assert 1==1
输出结果:
test_sample.py 前置条件,初始化列表
this is my fixture
first case
列表长度为:
1
.this is my fixture
second case
列表长度为:
1
.后置条件,清空列表
​

由此可以看出,整个类,值初始化了一次列表

四、conftest.py共享夹具函数

conftest特点:

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

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

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

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

5、conftest.py文件不能被其他文件导入

6、所有同目录测试文件运行前都会执行conftest.py文件。

conftest结合fixture的使用:

1、conftest中fixture的scope参数为session,所有测试.py文件执行前执行一次

2、conftest中fixture的scope参数为module,每一个测试.py文件执行前都会执行一次conftest文件中的fixture

3、conftest中fixture的scope参数为class,每一个测试文件中的测试类执行前都会执行一次conftest文件中的fixture

4、conftest中fixture的scope参数为function,所有文件的测试用例执行前都会执行一次conftest文件中的fixture

conftest应用场景:

1、每个接口需共用到的token

2、每个接口需共用到的测试用例数据

3、每个接口需共用到的配置信息

4、数据库的初始化连接、关闭

5、打开浏览器、关闭浏览器

示例

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

# 根目录下conftest.py
import pytest
@pytest.fixture(scope='session')
def login_session():
    print("初始化session")
    session='123456789'
    return session
​
#a目录下的test_a.py文件
import pytest
def test1(login_session):
    session='123456789'
    print('执行a目录下的test1方法,获取login_session:%s'%login_session)
    assert session==login_session
​
#b目录下的test_sample.py文件
def test2(login_session):
    session='123456789'
    print('执行b目录下的test2方法,获取login_session:%s'%login_session)
    assert session==login_session
输出结果:
D:\pytest\learn01>pytest -v -s a/test_a.py b/test_sample.py
========================================================================================== test session starts ===========================================================================================
platform win32 -- Python 3.7.3, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- d:\python3.7\python\python3.exe
cachedir: .pytest_cache
rootdir: D:\pytest\learn01, configfile: pytest.ini
collected 2 items                                                                                                                                                                                        
a/test_a.py::test1 初始化session
执行a目录下的test1方法,获取login_session:123456789
PASSED
b/test_sample.py::test2 执行b目录下的test2方法,获取login_session:123456789
PASSED
​

五、夹具终止 / 执行 teardown 代码

pytest支持当夹具超出作用域时,执行特定夹具的清理代码。可以通过使用yield替换return,可以实现teardown的功能,所有在yield之后的代码将会执行清理工作。

# content of conftest.py
import smtplib
import pytest
​
@pytest.fixture(scope="module")
def smtp_connection():
    smtp_connection = smtplib.SMTP("smtp.qq.com", 587, timeout=5)
    yield smtp_connection # provide the fixture value
    print("teardown smtp")
    smtp_connection.close()
# content of test_c.py
def test_conn(smtp_connection):
    response, msg = smtp_connection.ehlo()
    assert response == 250
    assert b"smtp.qq.com" in msg
    assert 0 # for demo purposes
输出结果:
D:\pytest\learn01>pytest -v -s a/test_c.py
========================================================================================== test session starts ===========================================================================================
platform win32 -- Python 3.7.3, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- d:\python3.7\python\python3.exe
cachedir: .pytest_cache
rootdir: D:\pytest\learn01, configfile: pytest.ini
collected 1 item                                                                                                                                                                                          
a/test_c.py::test_conn FAILEDteardown smtp
其他内容省略

可以看出,print 和 smtp.close()会在模块的最后一个用例执行完成之后执行,不管测试执行的状态如何。

也可以结合with 来使用yield:

import smtplib
import pytest
​
@pytest.fixture(scope="module")
def smtp_connection():
    with smtplib.SMTP("smtp.qq.com", 587, timeout=5) as smtp_connection:
         yield smtp_connection # provide the fixture value

需要注意的是,如果在setup的过程中(yield关键字之前)发生异常,teardown的代码就不会运行。另一个执行teardown代码的可选方法是利用上下文request对象的addfinalizer方法来注册一个结束方法。 下面是夹具使用 addfininalizer进行清理的方法:

import pytest
​
@pytest.fixture()
def myfixture(request):
    print ("执行固件myfixture的前半部分")
    def myteardown():
        print("执行固件myfture的后半部分")
    request.addfinalizer(myteardown)
​
​
class Test_Pytest():
​
        def test_one(self,myfixture):
                print("test_one方法执行" )
                assert 1==1
​
        def test_two(self):
                print("test_two方法执行" )
                assert "o" in "love"
​
        def test_three(self):
                print("test_three方法执行" )
                assert 3-2==1
输出结果:
D:\pytest\learn01>pytest -s a/test_a.py
========================================================================================== test session starts ===========================================================================================
platform win32 -- Python 3.7.3, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: D:\pytest\learn01, configfile: pytest.ini
collected 3 items                                                                                                                                                                                         
​
a\test_a.py 执行固件myfixture的前半部分
test_one方法执行
.执行固件myfture的后半部分
test_two方法执行
.test_three方法执行
.

参考文献:https://www.cnblogs.com/miki-peng/p/14736425.html

https://www.cnblogs.com/yoyoketang/tag/pytest/

— 于 共写了6609个字
— 标签:

评论已关闭。