• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Pytest测试框架二环境初始化和数据清除

武飞扬头像
凡晨丹心
帮助1

一、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

这篇好文章是转载于:编程之路

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 编程之路
  • 本文地址: /boutique/detail/tanhhgbceg
系列文章
更多 icon
同类精品
更多 icon
继续加载