pytest框架进阶自学系列 | 不同层级scope使用fixture实例

书籍来源:房荔枝 梁丽丽《pytest框架与自动化测试应用》

一边学习一边整理老师的课程内容及实验笔记,并与大家分享,侵权即删,谢谢支持!

附上汇总贴:pytest框架进阶自学系列 | 汇总_热爱编程的通信人的博客-CSDN博客


fixture(scope="function",params=None,autouse=False,ids=None,name=None):scope有5个级别参数function(默认)、class、module、package和session。package被认为是实验性的。

  • function:每个函数或方法都会调用;
  • class:每个类调用一次,一个类可以有多种方法;
  • module:每个.py文件调用一次,该文件内又有多个function和class;
  • Session:多个文件调用一次,可以跨.py文件调用,每个.py文件就是module。

如何使用fixture功能实现不同层级的数据共享呢?默认的function级别已经举例说明了,也就是每种方法都可以调用fixture标记的方法,通过传参的方式。

现在来举个module层级的例子,module是模块级,也就是每个文件只调用一次。

模块(module)级别使用fixture实例

常用使用场景:当进行测试执行时,有些动作只在这个文件中的开始或结束执行一次。这就需要运用层级scope的设置了,当把scope参数设置为module时,只在文件开始执行一次。例如,在进行WebUI自动化测试时,需要在测试用例前打开浏览器这个动作。

实现步骤:

(1)导入pytest。

(2)创建open()函数。

(3)在open()函数上添加@pytest.fixture(scope="module")。

(4)在测试方法中传入参数(open函数名称)。

具体代码如下:

import pytest

@pytest.fixture(scope="module")
def open():
    print("打开浏览器,打开百度首页")

def test_s7():
    print('用例7,')

def test_s8(open):
    print('用例8,')

def test_s9(open):
    print('用例9,')

全部添加open参数时执行结果如下:

D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:/Program Files/JetBrains/PyCharm Community Edition 2022.3.2/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --path D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_module.py 
Testing started at 13:46 ...
Launching pytest with arguments D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_module.py in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3

============================= test session starts =============================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1 -- D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe
cachedir: .pytest_cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book
collecting ... collected 3 items

test_fixture_module.py::test_s7 打开浏览器,打开百度首页
PASSED                                   [ 33%]用例7,

test_fixture_module.py::test_s8 PASSED                                   [ 66%]用例8,

test_fixture_module.py::test_s9 PASSED                                   [100%]用例9,


============================== 3 passed in 0.26s ==============================

Process finished with exit code 0

s7()函数不添加open参数时执行结果如下:

D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:/Program Files/JetBrains/PyCharm Community Edition 2022.3.2/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --path D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_module.py 
Testing started at 13:46 ...
Launching pytest with arguments D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_module.py in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3

============================= test session starts =============================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1 -- D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe
cachedir: .pytest_cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book
collecting ... collected 3 items

test_fixture_module.py::test_s7 PASSED                                   [ 33%]用例7,

test_fixture_module.py::test_s8 打开浏览器,打开百度首页
PASSED                                   [ 66%]用例8,

test_fixture_module.py::test_s9 PASSED                                   [100%]用例9,


============================== 3 passed in 0.06s ==============================

Process finished with exit code 0

其他执行结果,读者可以自行体会。因为module作用于全文件,可以分几种情况:open在第一种方法中使用,其他方法可以不添加。open方法在全文件开始前只执行一次。如果第一种方法中没有open,则第一种方法单独执行,再执行下面的第二种方法,也就是说,open添加在哪个测试方法中,就从该方法以后实现open依赖注入效果。

类(class)级别使用fixture实例

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

代码如下:

import pytest

@pytest.fixture(scope="class")
def first():
    print("\n获取用户名,scope为class级别只运行一次")
    a = "linda"
    return a

def test_3():
    print("不在类中的测试方法")
    
class TestCase():
    def test_1(self, first):
        print("测试账号:%s" % first)
        assert first == "linda"
        
    def test_2(self, first):
        print("测试账号:%s" % first)
        assert first == "linda"

执行的结果如图3-3所示。

会话(session)级别使用fixture与conftest.py配合

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

既然已经是跨模块,需要在.py模块之上。因此采用一个单独的文件conftest.py,文件名称是固定的,pytest会自动识别该文件。放到工程的根目录下就可以全局调用了,如果放到某个package包下,那就只在该package内有效。

D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:/Program Files/JetBrains/PyCharm Community Edition 2022.3.2/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --path D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_class.py 
Testing started at 13:51 ...
Launching pytest with arguments D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_class.py in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3

============================= test session starts =============================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1 -- D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe
cachedir: .pytest_cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book
collecting ... collected 3 items

test_fixture_class.py::test_3 PASSED                                     [ 33%]不在类中的测试方法

test_fixture_class.py::TestCase::test_1 
获取用户名,scope为class级别只运行一次
PASSED                           [ 66%]测试账号:linda

test_fixture_class.py::TestCase::test_2 PASSED                           [100%]测试账号:linda


============================== 3 passed in 0.02s ==============================

Process finished with exit code 0

常用使用场景:当用户与其他测试工程师合作开发时,公共的模块要存放在不同文件中,要存放在大家都能访问的地方。通常是一些公用的配置。公共模块也可以,例如登录模块是大家公用的,因此应放在项目或包的路径下。

具体执行步骤如下:

(1)在本目录下创建conftest.py文件(文件名必须是这个)。

(2)将登录模块带@pytest.fixture写在conftest.py文件中。

import pytest

@pytest.fixture()
def login():
    print("\n用户名linda密码登录!")

(3)在原来的test_fixture.py文件中删除部分代码(login方法),代码如下:

import pytest

def test_cart(login):
    print('\n用例1,登录后执行查看购物车其他功能1')

def test_find_goods():
    print('\n用例2,不登录,执行浏览商品功能2')

def test_pay(login):
    print('\n用例3,登录后执行支付功能3')

(4)右击鼠标,选择pytest执行test_fixture.py。

在执行过程中当读到login时,如果在本用例中没找到,则去本目录下conftest.py中查找。如果找到就执行,如果找不到就报错。同时其他工程师也可以在本目录中新建文件,并使用login函数,可以跟上述代码类似。

D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:/Program Files/JetBrains/PyCharm Community Edition 2022.3.2/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --path D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture.py 
Testing started at 13:53 ...
Launching pytest with arguments D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture.py in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3

============================= test session starts =============================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1 -- D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe
cachedir: .pytest_cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book
collecting ... collected 3 items

test_fixture.py::test_cart 
用户名linda密码登录!
PASSED                                        [ 33%]
用例1,登录后执行查看购物车其他功能1

test_fixture.py::test_find_goods PASSED                                  [ 66%]
用例2,不登录,执行浏览商品功能2

test_fixture.py::test_pay 
用户名linda密码登录!
PASSED                                         [100%]
用例3,登录后执行支付功能3


============================== 3 passed in 0.18s ==============================

Process finished with exit code 0

session级别实例

需要使用网络接入的fixture往往依赖于网络的连通性,并且创建过程一般非常耗时。放在全局conftest.py文件中,类似一个单例模式的方法,提前建立连接,所有人可以使用这个连接。

(1)创建conftest.py文件,把网络连接的函数写在这个文件中,代码如下:

import pytest
import smtplib

@pytest.fixture()
def login():
    print("\n用户名linda密码登录!")
    
@pytest.fixture(scope='module')
def smtp_connection():
    return smtplib.SMTP("smtp.163.com", 25, timeout=5)

(2)在相同的目录下,新建一个测试模块test_module.py,将smtp_connection作为形参传入每个测试用例,它们共享同一个smtp_connection()的返回值。

def test_ehlo(smtp_connection):
    response, _ = smtp_connection.ehlo()
    assert response == 250
    smtp_connection.extra_attr = 'test'
    assert 0
    
def test_noop(smtp_connection):
    response, _ = smtp_connection.noop()
    assert response == 250
    assert smtp_connection.extra_attr == 0

(3)执行这个测试模块,结果如下:

可以看到:两个测试用例使用的smtp_connection实例都是<smtplib.SMTP object at 0x1104bbe48>,说明smtp_connection只被调用了一次。在前一个用例test_ehlo中修改smtp_connection实例(上述例子中,为smtp_connection添加extra_attr属性),也会反映到test_noop用例中,如图3-5所示。

D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:/Program Files/JetBrains/PyCharm Community Edition 2022.3.2/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --path D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_module.py 
Testing started at 13:57 ...
Launching pytest with arguments D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_module.py in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3

============================= test session starts =============================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1 -- D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe
cachedir: .pytest_cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book
collecting ... collected 2 items

test_module.py::test_ehlo FAILED                                         [ 50%]
src\chapter-3\test_module.py:0 (test_ehlo)
smtp_connection = <smtplib.SMTP object at 0x000001C1E8D31188>

    def test_ehlo(smtp_connection):
        response, _ = smtp_connection.ehlo()
        assert response == 250
        smtp_connection.extra_attr = 'test'
>       assert 0
E       assert 0

test_module.py:5: AssertionError
FAILED                                         [100%]
src\chapter-3\test_module.py:6 (test_noop)
'test' != 0

Expected :0
Actual   :'test'
<Click to see difference>

smtp_connection = <smtplib.SMTP object at 0x000001C1E8D31188>

    def test_noop(smtp_connection):
        response, _ = smtp_connection.noop()
        assert response == 250
>       assert smtp_connection.extra_attr == 0
E       AssertionError: assert 'test' == 0
E         +'test'
E         -0

test_module.py:10: AssertionError







test_module.py::test_noop 

================================== FAILURES ===================================
__________________________________ test_ehlo __________________________________

smtp_connection = <smtplib.SMTP object at 0x000001C1E8D31188>

    def test_ehlo(smtp_connection):
        response, _ = smtp_connection.ehlo()
        assert response == 250
        smtp_connection.extra_attr = 'test'
>       assert 0
E       assert 0

test_module.py:5: AssertionError
__________________________________ test_noop __________________________________

smtp_connection = <smtplib.SMTP object at 0x000001C1E8D31188>

    def test_noop(smtp_connection):
        response, _ = smtp_connection.noop()
        assert response == 250
>       assert smtp_connection.extra_attr == 0
E       AssertionError: assert 'test' == 0
E         +'test'
E         -0

test_module.py:10: AssertionError
=========================== short test summary info ===========================
FAILED test_module.py::test_ehlo - assert 0
FAILED test_module.py::test_noop - AssertionError: assert 'test' == 0
============================== 2 failed in 0.60s ==============================

Process finished with exit code 1

如果期望拥有一个会话级别作用域的fixture,则可以简单地将其声明为session。

import pytest
import smtplib

@pytest.fixture()
def login():
    print("\n用户名linda密码登录!")

@pytest.fixture(scope='session')
def smtp_connection():
    return smtplib.SMTP("smtp.163.com", 25, timeout=5)

注意:pytest每次只缓存一个fixture实例,当使用参数化的fixture时,pytest可能会在声明的作用域内多次调用这个fixture。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值