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
  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
pytest框架本身并不提供专门的数据管理功能,但可以通过使用pytest的fixture功能和其他库来实现web自动化测试数据的管理。 一种常见的方法是使用pytest的fixture功能来创建测试数据。fixture是pytest中的一个装饰器,可以在测试用例执行前后执行一些预设的操作,比如创建测试数据。你可以在conftest.py文件中定义fixture,然后在测试用例中使用它。 以下是一个示例,演示了如何使用pytest的fixture来管理web自动化测试数据: ```python # conftest.py import pytest @pytest.fixture def login_data(): # 在这里可以编写代码来获取登录所需的测试数据 username = "testuser" password = "testpassword" return username, password @pytest.fixture def search_data(): # 在这里可以编写代码来获取搜索所需的测试数据 keyword = "testkeyword" return keyword ``` ```python # test_web.py def test_login(login_data): username, password = login_data # 在这里编写登录测试用例的代码,使用username和password进行登录操作 def test_search(search_data): keyword = search_data # 在这里编写搜索测试用例的代码,使用keyword进行搜索操作 ``` 在上面的示例中,我们在conftest.py文件中定义了两个fixture:login_data和search_data。这些fixture会在测试用例执行前被调用,并返回相应的测试数据。在test_web.py文件中,我们通过将fixture作为参数传递给测试用例函数来使用这些测试数据。 除了使用pytest的fixture功能外,你还可以结合其他库来管理web自动化测试数据。例如,你可以使用Excel或CSV文件来存储测试数据,并使用相应的库(如openpyxl或csv)来读取和处理这些文件。 总结一下,pytest框架本身并不提供专门的数据管理功能,但可以通过使用pytest的fixture功能和其他库来实现web自动化测试数据的管理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凡晨丹心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值