IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> Pytest测试框架(二)环境初始化与数据清除 -> 正文阅读

[开发测试]Pytest测试框架(二)环境初始化与数据清除

一、fixture的用途

pytest fixture 与setup,teardown功能一样,但比之更加灵活,完全可以代替setup,teardown

1.做测试前后的初始化设置,如测试数据准备,链接数据库,打开浏览器等这些操作都可以使用fixture来实现

2.测试用例的前置条件可以使用fixture实现

3.支持经典的xunit fixture ,像unittest使用的setup和teardown

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

二、fixture的定义

fixture通过@pytest.fixture()装饰器装饰一个函数,那么这个函数就是一个fixture

import pytest


@pytest.fixture()
def login():
    print('登陆方法')
    yield   #激活fixture teardown方法
    print('teardown')

# 测试用例之前,先执行login方法
def test_case1(login):
    print('case1')

def test_case2():
    print('case2')

def test_case3():
    print('case3')

运行结果如下:

test_login.py::test_case2 
test_login.py::test_case3 

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

Process finished with exit code 0
登陆方法
PASSED                                         [ 33%]case1
teardown
PASSED                                         [ 66%]case2
PASSED                                         [100%]case3

三、共享 fixture 函数:conftest.py

1.conftest.py文件名字是固定的,不可以做任何修改

2.文件和用例文件在同一个目录下,那么conftest.py作用于整个目录

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

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

在测试过程中,多个测试文件可能都要调用 fixture 函数,可以将其移动到 conftest.py 文件中。conftest.py 文件中的 fixture 函数不需要在测试函数中导入,可以被 pytest 自动识别,查找顺序从测试类开始,然后是测试模块,然后是 conftest.py 文件,最后是内置插件和第三方插件。

conftest.py :

import pytest
@pytest.fixture()
def login():
    print("登录")
    return 8

测试用例:

import pytest

class Test_Demo():
    def test_case1(self):
        print("\n开始执行测试用例1")
        assert 1 + 1 == 2

    def test_case2(self, login):
        print("\n开始执行测试用例2")
        print(login)
        assert 2 + login == 10

    def test_case3(self):
        print("\n开始执行测试用例3")
        assert 99 + 1 == 100


if __name__ == '__main__':
    pytest.main()

结果如下:

PASSED                           [ 33%]
开始执行测试用例1
登录
PASSED                           [ 66%]
开始执行测试用例2
8
PASSED                           [100%]
开始执行测试用例3

四、yield方法

使用yield关键字可以实现setup/teardown的功能,在yield关键字之前的代码在case之前执行,yield之后的代码在case运行结束后执行

import pytest

@pytest.fixture()
def login():
    print("登录")
    yield
    print("退出登录")

class Test_Demo():
    def test_case1(self):
        print("\n开始执行测试用例1")
        assert 1 + 1 == 2

    def test_case2(self, login):
        print("\n开始执行测试用例2")
        assert 2 + 8 == 10

    def test_case3(self):
        print("\n开始执行测试用例3")
        assert 99 + 1 == 100


if __name__ == '__main__':
    pytest.main()

结果如下:

PASSED                      [ 33%]
开始执行测试用例1
登录
PASSED                      [ 66%]
开始执行测试用例2
退出登录
PASSED                      [100%]
开始执行测试用例3


五、addfinalizer方法

addfinalizer也可以实现环境的清理,实现与yield方法相同的效果,跟yield不同的是需要注册作为终结器使用的函数。

import pytest

@pytest.fixture()
def login(request):
    print("登录")
    def demo_finalizer():
        print("退出登录")
    # 注册demo_finalizer为终结函数
    request.addfinalizer(demo_finalizer)

class Test_Demo():
    def test_case1(self):
        print("\n开始执行测试用例1")
        assert 1 + 1 == 2

    def test_case2(self, login):
        print("\n开始执行测试用例2")
        assert 2 + 8 == 10

    def test_case3(self):
        print("\n开始执行测试用例3")
        assert 99 + 1 == 100


if __name__ == '__main__':
    pytest.main()

运行结果如下:

PASSED               [ 33%]
开始执行测试用例1
登录
PASSED               [ 66%]
开始执行测试用例2
退出登录
PASSED               [100%]
开始执行测试用例3


六、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的作用范围(scope)

(一)、conftest结合fixture的使用

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

  • function 每一个函数或方法都会调用,默认为function
  • class 每一个类调用一次,一个类可以有多个方法
  • module(.py文件),每一个.py文件调用一次,该文件内又有多个function和class
  • session(包) 是多个文件调用一次,可以跨.py文件调用,每个.py文件就是module

(二)、conftest应用场景

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

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

3、每个接口需共用到的配置信息
1、scope='function’

import pytest

@pytest.fixture()   #默认为scope='function'
def login():
    print('登陆方法')
    yield ['username','passwd']  #激活fixture teardown方法
    print('teardown')

# 测试用例之前,先执行login方法
def test_case1(login):
    print(f'case1 login={login}')

def test_case2(login):
    print('case2')

def test_case3(login):
    print('case3')

运行结果如下:

============================= test session starts ==============================
platform darwin -- Python 3.6.4, pytest-6.0.2, py-1.9.0, pluggy-0.13.1 -- /usr/local/bin/python3.6
cachedir: .pytest_cache
rootdir: /Users/chenshifeng/MyCode/PythonCode/SFDSZL/test_pytest, configfile: pytest.ini
collecting ... collected 3 items

test_login.py::test_case1 
test_login.py::test_case2 
test_login.py::test_case3 

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

Process finished with exit code 0
登陆方法
PASSED                                         [ 33%]case1 login=['username', 'passwd']
teardown
登陆方法
PASSED                                         [ 66%]case2
teardown
登陆方法
PASSED                                         [100%]case3
teardown

2、scope=“class”
一个class里面多个用例都调用了此fixture,那么只在class里所有用例开始前执行一次

import pytest

@pytest.fixture(scope="class")
def login():
    print("登录...")



结果:

登录...
PASSED                      [ 33%]
开始执行测试用例1
PASSED                      [ 66%]
开始执行测试用例2
PASSED                      [100%]
开始执行测试用例3


3、scope='module’

import pytest


@pytest.fixture(scope='module')   #默认为scope='function'
def login():
    print('登陆方法')
    yield ['username','passwd']  #激活fixture teardown方法
    print('teardown')

# 测试用例之前,先执行login方法
def test_case1(login):
    print(f'case1 login={login}')

def test_case2(login):
    print('case2')

def test_case3(login):
    print('case3')

运行结果如下:

============================= test session starts ==============================
platform darwin -- Python 3.6.4, pytest-6.0.2, py-1.9.0, pluggy-0.13.1 -- /usr/local/bin/python3.6
cachedir: .pytest_cache
rootdir: /Users/chenshifeng/MyCode/PythonCode/SFDSZL/test_pytest, configfile: pytest.ini
collecting ... collected 3 items

test_login.py::test_case1 
test_login.py::test_case2 
test_login.py::test_case3 

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

Process finished with exit code 0
登陆方法
PASSED                                         [ 33%]case1 login=['username', 'passwd']
PASSED                                         [ 66%]case2
PASSED                                         [100%]case3
teardown

4、scope='session’
可以实现全局变量

多个.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

八、fixture自动调用(autouse=True)

autouse设置为True时,自动调用fixture功能。由于默认作用域为function,不指定scope则每个方法都会调用fixture方法。

import pytest


@pytest.fixture(autouse=True)  # 默认为scope='function'
def login():
    print('登陆方法')
    yield ['username', 'passwd']  # 激活fixture teardown方法
    print('teardown')
    
def test_search1():  #无需继承login
    print('搜索用例1')

def test_search2():
    print('搜索用例2')

运行结果如下:

============================= test session starts ==============================
test_search.py::test_search1 登陆方法
PASSED                                      [ 50%]搜索用例1
teardown

test_search.py::test_search2 登陆方法
PASSED                                      [100%]搜索用例2
teardown


============================== 2 passed in 0.01s ===============================

Process finished with exit code 0

九、fixture参数化(params)

@pytest.fixture有一个params参数,接受一个列表,列表中每个数据都可以作为用例的输入。也就说有多少数据,就会形成多少用例。可以通过’’‘request.param’’'来获取该次调用的参数。

import pytest


@pytest.fixture(params=['user1', 'user2', 'user3'])
def login(request):
    print('登陆方法')
    print('传入的参数为:'+request.param)  # 获取params参数
    yield ['username', 'passwd']  # 激活fixture teardown方法
    print('teardown')

# 测试用例之前,先执行login方法
def test_case1(login):
    print(f'case1 login={login}')

def test_case2(login):
    print('case2')

def test_case3(login):
    print('case3')

运行结果如下:

test_login.py::test_case1[user1] 
test_login.py::test_case1[user2] 
test_login.py::test_case1[user3] 
test_login.py::test_case2[user1] 
test_login.py::test_case2[user2] 
test_login.py::test_case2[user3] 
test_login.py::test_case3[user1] 登陆方法
传入的参数为:user1
PASSED                                  [ 11%]case1 login=['username', 'passwd']
teardown
登陆方法
传入的参数为:user2
PASSED                                  [ 22%]case1 login=['username', 'passwd']
teardown
登陆方法
传入的参数为:user3
PASSED                                  [ 33%]case1 login=['username', 'passwd']
teardown
登陆方法
传入的参数为:user1
PASSED                                  [ 44%]case2
teardown
登陆方法
传入的参数为:user2
PASSED                                  [ 55%]case2
teardown
登陆方法
传入的参数为:user3
PASSED                                  [ 66%]case2
teardown
登陆方法
传入的参数为:user1
PASSED                                  [ 77%]case3
teardown

test_login.py::test_case3[user2] 登陆方法
传入的参数为:user2
PASSED                                  [ 88%]case3
teardown

test_login.py::test_case3[user3] 登陆方法
传入的参数为:user3
PASSED                                  [100%]case3
teardown


============================== 9 passed in 0.06s ===============================

十、参数化与fixture结合(indirect=True)

import pytest


@pytest.fixture(params=['user1', 'user2', 'user3'])
def login(request):
    print('登陆方法')
    print('传入的参数为:' + str(request.param))  # 获取params参数
    yield ['username', 'passwd']  # 激活fixture teardown方法
    print('teardown')


# 参数化结合fixture使用
# 情况一:传入值和数据
# 情况二:传入一个fixture方法,将数据传入到fixture方法中,fixture使用request参数来接受这组数据,在方法体中使用request.param来接受这个数据
@pytest.mark.parametrize('login', [
    ('username1', 'passwd1'),
    ('username2', 'passwd2')
], indirect=True)
def test_cart3(login):
    print('购物车用例3')

运行结果如下:

test_cart.py::test_cart3[login0] 
test_cart.py::test_cart3[login1] 

============================== 2 passed in 0.02s ===============================

Process finished with exit code 0
登陆方法
传入的参数为:('username1', 'passwd1')
PASSED                                  [ 50%]购物车用例3
teardown
登陆方法
传入的参数为:('username2', 'passwd2')
PASSED                                  [100%]购物车用例3
teardown
  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-09-07 11:07:04  更:2021-09-07 11:08:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/18 0:36:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码