pytest框架进阶自学系列 | 使用params传递不同数据

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

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

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


fixture(scope="function",params=None,autouse=False,ids=None,name=None),params是参数,默认可以不选。

如果需要在一系列测试用例的执行中,每轮执行都使用同一个fixture,但是有不同的依赖场景,则可以考虑对fixture进行参数化,这种方式适用于对多场景的功能模块进行详尽测试。

可以通过指定params关键字参数创建两个fixture实例,每个实例供一轮测试使用,所有的测试用例执行两遍,在fixture的声明函数中,可以使用request.param获取当前使用的入参。

测试方法使用两个简单测试数据

每次执行应使用不同数据,一次应使用一个。可以通过fixture自带的params准备不同的数据。下面是一个测试方法使用2个简单测试数据。

代码如下:

import pytest

@pytest.fixture(params=['apple', 'banana'])
def fruit(request):
    return request.param

def test_fruit(fruit):
    print("\n笔者今天吃{}".format(fruit))
    assert True
    
def test_cook_fruit(fruit):
    print("笔者今天做{}派。".format(fruit))
    assert True

执行结果如下所示:

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_params.py 
Testing started at 14:11 ...
Launching pytest with arguments D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_params.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 4 items

test_fixture_params.py::test_fruit[apple] PASSED                         [ 25%]
笔者今天吃apple

test_fixture_params.py::test_fruit[banana] PASSED                        [ 50%]
笔者今天吃banana

test_fixture_params.py::test_cook_fruit[apple] PASSED                    [ 75%]笔者今天做apple派。

test_fixture_params.py::test_cook_fruit[banana] PASSED                   [100%]笔者今天做banana派。


============================== 4 passed in 0.04s ==============================

Process finished with exit code 0

二(多)个测试方法共用两个简单测试数据

在代码中增加下述代码,实现多个测试使用一组不同数据:

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_params.py 
Testing started at 14:11 ...
Launching pytest with arguments D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_params.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 4 items

test_fixture_params.py::test_fruit[apple] PASSED                         [ 25%]
笔者今天吃apple

test_fixture_params.py::test_fruit[banana] PASSED                        [ 50%]
笔者今天吃banana

test_fixture_params.py::test_cook_fruit[apple] PASSED                    [ 75%]笔者今天做apple派。

test_fixture_params.py::test_cook_fruit[banana] PASSED                   [100%]笔者今天做banana派。


============================== 4 passed in 0.04s ==============================

Process finished with exit code 0

有效测试数据与预期失败xfail的测试数据

在测试某些功能时,如果步骤一致,则可以使用数据驱动方式执行测试,也就是说多组数据使用一个测试方法。通常正确有效的数据分得一个测试方法,因为错误的步骤通常简单,而正确的步骤会多些,必须分开验证,但当步骤相同而数据不同时,预期失败和预期正确的数据可以在一个测试方法中实现。这样就只有一组或几组数据会引起预期的失败,但不能在测试方法中标记预期失败,而应该在通过参数传递的测试数据中使用pytest.param标记预期失败。

代码如下:

import pytest

@pytest.fixture(params=[('3+5', 8), pytest.param(('6*9', 42), marks=pytest.mark.xfail, ids='failed')])
def data_set(request):
    return request.param

def test_data(data_set):
    assert eval(data_set[0]) == data_set[1]

在data_set方法中使用request传递fixture中的参数,使用request.param解析每个参数。在方法上面加上pytest.fixture装饰器,通过参数传递不同的测试数据。一组是正确的,3+5和8比对,另一组将6*9和42比对,并且在test_data中通过data_set的依赖注入的方式传入数据,通过eval方法将表达式,例如3+5从字符串转换成可执行的算式,计算的结果与传递参数的第二列data_set[1]数据比对是否相等。

最重要的是第二组数据预期结果不正确,通过marks标记成失败pytest.mark.xfail,并用ids显示出failed。

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_param_marks.py 
Testing started at 14:19 ...
Launching pytest with arguments D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_param_marks.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_fixture_param_marks.py::test_data[data_set0] 
test_fixture_param_marks.py::test_data[failed] 

======================== 1 passed, 1 xfailed in 0.08s =========================

Process finished with exit code 0
PASSED                 [ 50%]XFAIL                     [100%]
data_set = ('6*9', 42)

    def test_data(data_set):
>       assert eval(data_set[0]) == data_set[1]
E       assert 54 == 42
E         +54
E         -42

test_fixture_param_marks.py:8: AssertionError

params与ids的应用

对于复杂类型的测试数据通常加上id或name来表明数据的含义,并标记测试要点。测试数据除了字符串以外,还可以是表达式,以及元组、字典、类等类型。使用ids关键字参数,自定义测试ID。

代码如下:

import pytest

@pytest.fixture(params=[0, 'a'], ids=['number', 'charactor'])
def a(request):
    return request.param 

def test_a(a):
    print(a)
    pass

def idfn(fixture_value):
    if fixture_value == 0:
        return "eggs"
    elif fixture_value == 1:
        return False
    elif fixture_value == 2:
        return None
    else:
        return fixture_value
    
@pytest.fixture(params=[0,1,2,3], ids=idfn)
def b(request):
    return request.param

def test_b(b):
    print(b)
    pass

class C:
    pass

@pytest.fixture(params=[(1,2), {'d':1}, C()])
def c(request):
    return request.param

def test_c(c):
    print(c)
    pass

ids=idfn,idfn是前面使用的方法,在fixture中将params的每个数据传入idfn,ids的值就是其返回值。当params=0时,返回值eggs;当params=1时,返回值False;当params=2时,返回值None,ids显示params的值;当params=3时,返回值直接显示为3。

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_params_ids.py 
Testing started at 14:24 ...
Launching pytest with arguments D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_params_ids.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 9 items

test_fixture_params_ids.py::test_a[number] PASSED                        [ 11%]0

test_fixture_params_ids.py::test_a[charactor] PASSED                     [ 22%]a

test_fixture_params_ids.py::test_b[eggs] PASSED                          [ 33%]0

test_fixture_params_ids.py::test_b[False] PASSED                         [ 44%]1

test_fixture_params_ids.py::test_b[2] PASSED                             [ 55%]2

test_fixture_params_ids.py::test_b[3] PASSED                             [ 66%]3

test_fixture_params_ids.py::test_c[c0] PASSED                            [ 77%](1, 2)

test_fixture_params_ids.py::test_c[c1] PASSED                            [ 88%]{'d': 1}

test_fixture_params_ids.py::test_c[c2] PASSED                            [100%]<test_fixture_params_ids.C object at 0x0000023D0F1A5388>


============================== 9 passed in 0.09s ==============================

Process finished with exit code 0

从执行结果可以看出:ids可以接收一个函数,用于生成测试ID。当测试ID指定为None时,使用的是params原先对应的值。

注意:当测试params中包含元组、字典或者对象时,测试ID使用的是fixture函数名+param的下标。

如果使用CLI终端执行,则结果如下:

PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3> pytest -s -v .\test_fixture_params_ids.py 
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1 -- c:\users\guoliang\appdata\local\programs\python\python37\python.exe
cachedir: .pytest_cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book
plugins: allure-pytest-2.13.2
collected 9 items                                                                                                                                                                                                                       

test_fixture_params_ids.py::test_a[number] 0
PASSED
test_fixture_params_ids.py::test_a[charactor] a
PASSED
test_fixture_params_ids.py::test_b[eggs] 0
PASSED
test_fixture_params_ids.py::test_b[False] 1
PASSED
test_fixture_params_ids.py::test_b[2] 2
PASSED
test_fixture_params_ids.py::test_b[3] 3
PASSED
test_fixture_params_ids.py::test_c[c0] (1, 2)
PASSED
test_fixture_params_ids.py::test_c[c1] {'d': 1}
PASSED
test_fixture_params_ids.py::test_c[c2] <test_fixture_params_ids.C object at 0x0000022B6155BF48>
PASSED

========================================================================================================== 9 passed in 0.03s ========================================================================================================== 
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3>

params综合实例

这个测试用例使用不同的SMTP服务器,共执行了3次。在参数化的fixture中,pytest为每个fixture实例自动指定一个测试ID。

import pytest
import smtplib

@pytest.fixture(scope='module', params=['smtp.163.com', 'smtp.126.com', 'mail.python.org'])
def smtp_connection_params(request):
    server = request.param
    with smtplib.SMTP(server, 587, timeout=5) as smtp_connection:
        yield smtp_connection
        
def test_parames(smtp_connection_params):
    response, _ = smtp_connection_params.ehlo()
    assert response == 250

可以看到执行显示的ID是test_parames[http://smtp.163.com]、test_parames[http://smtp.126.com]、test_parames[http://mail.python.org]。

图3-10 param的综合实例

PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3> pytest -q -s --collect-only .\test_request.py
src/chapter-3/test_request.py::test_parames[smtp.163.com]
src/chapter-3/test_request.py::test_parames[smtp.126.com]
src/chapter-3/test_request.py::test_parames[mail.python.org]

no tests ran in 0.01s
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值