天天看点

pytest框架进阶自学系列 | 在不同的层级上重写fixture

作者:热爱编程的通信人

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

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

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

在大型测试中,可能需要在本地覆盖项目级别的fixture,以增加可读性和可维护性。也就是说可以通过在不同层级中重写fixture改变fixture中原始的内容。思路是重写同名(文件或函数)的方法。使用时优先调用重写后的fixture。

在文件夹(conftest.py)层级重写fixture

下一层的conftest.py中的fixtures可以覆盖和访问上一级的fixture,实现过程:

  1. 在不同层次建立文件夹

创建tests文件夹,以及子文件夹subfolder。在tests文件夹下面创建conftest.py文件和test_something.py两个文件,在subfolder下同样创建这两个文件。

pytest框架进阶自学系列 | 在不同的层级上重写fixture
  1. 各个文件的代码

在tests文件夹下的conftest.py文件的fixture中创建username方法。

import pytest

@pytest.fixture
def username():
    return 'username'           

在tests文件夹下的test_something.py文件中创建test_username方法,通过断言判断传入的是否为username方法所返回的username字符串。

def test_username(username):
    assert username == 'username'           

在subfolder文件夹下的conftest.py文件的fixture中创建的username方法中调用username,也就是通过这个参数调用上一级conftest.py中username的fixture。通过同名的方法重写上一级的同名fixture方法。

import pytest

@pytest.fixture
def username(username):
    return 'overridden-' + username           

在subfolder文件夹下test_something.py文件的test_username测试方法中调用username,这时调用本地的方法,也就是subfolder文件夹下的conftest.py文件的username方法中重写上一级的usename方法,并通过断言测试是否是本地重写的结果。

def test_username(username):
    assert username == 'overridden-username'           

执行结果如下:

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

============================= 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_something.py::test_username PASSED                                  [ 50%]
subfolder\test_something.py::test_username PASSED                        [100%]

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

Process finished with exit code 0
           

子文件夹(subfolder)中conftest.py文件的fixture覆盖了上层文件夹中同名的fixture。

子文件夹(subfolder)中conftest.py文件的fixture可以轻松地访问上层文件夹中同名的fixture。

在模块层级重写fixture

在conftest.py及自己同一文件下的fixture具有相同名字,由在同一文件中的fixture函数重写了conftest.py中的fixture函数。也就是说模块(文件中)中的fixture覆盖了conftest.py中同名的fixture。模块(文件)中的fixture可以轻松地访问conftest.py中同名的fixture。

代码如下:

// test/test_something.py
import pytest

@pytest.fixture
def username(username):
    return 'overridden-' + username

def test_username(username):
    assert username == 'overridden-username'
    
// test/test_something_else.py
import pytest

@pytest.fixture
def username(username):
    return 'overridden-else-' + username

def test_username(username):
    assert username == 'overridden-else-username'           
D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2022.1.3\plugins\python-ce\helpers\pycharm\_jb_pytest_runner.py" --path D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests
Testing started at 12:02 ...
Launching pytest with arguments D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\tests

============================= 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_something.py::test_username PASSED                                  [ 33%]
test_something_else.py::test_username PASSED                             [ 66%]
subfolder\test_something.py::test_username PASSED                        [100%]

============================== 3 passed in 0.04s ==============================

Process finished with exit code 0
           

在用例参数中重写fixture

常用的使用场景:fixture通常作为测试数据的初始化,而参数化是调用这些数据实现一个测试方法使用不同数据执行多次的效果。在fixture与参数parametrize组合在一起时,在fixture中读到的原始值可以被用例的参数parametrize所覆盖,这可体现数据层级的灵活性。

代码如下:

// test/conftest.py
import pytest


@pytest.fixture
def username():
    return 'username'


@pytest.fixture
def other_username(username):
    return 'other-' + username
    
// test/test_something.py
import pytest

@pytest.mark.parametrize('username', ['directly-overridden-username'])
def test_username(username):
    assert username == 'directly-overridden-username'
    
@pytest.mark.parametrize('username', ['directly-overridden-username-other'])
def test_username_other(username, other_username):
    assert other_username == 'other-directly-overridden-username-other'           
D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2022.1.3\plugins\python-ce\helpers\pycharm\_jb_pytest_runner.py" --path D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests
Testing started at 12:09 ...
Launching pytest with arguments D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\tests

============================= 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_something.py::test_username[directly-overridden-username] PASSED    [ 25%]
test_something.py::test_username_other[directly-overridden-username-other] PASSED [ 50%]
test_something_else.py::test_username PASSED                             [ 75%]
subfolder\test_something.py::test_username PASSED                        [100%]

============================== 4 passed in 0.03s ==============================

Process finished with exit code 0
           

fixture的值被用例的参数所覆盖,尽管用例test_username_other没有使用username,但是other_username使用了username,所以也同样受到了影响。

参数化的fixture可重写非参数化的fixture,反之亦然

参数化的fixture和非参数化的fixture同样可以相互覆盖。其实就是在使用fixture的文件中建立同名的fixture方法重写上一级conftest.py文件中的同名方法。无论重写前的方法带参数,还是重写后的方法带参数都是可以的。也就是可以实现原来执行多次的方法通过重写为非参数化的fixture而变成只执行一次。同样可以实现原来只执行一次的方法通过重写为参数化的fixture而变成执行多次的参数化fixture。

代码如下:

import pytest

@pytest.fixture
def username():
    return 'username'

@pytest.fixture
def other_username(username):
    return 'other-' + username

@pytest.fixture(params=['one', 'two', 'three'])
def parametrized_username(request):
    return request.param

@pytest.fixture
def non_parametrized_username(request):
    return 'username'           

在test_something1.py文件中,创建与conftest.py文件中同名的parametrized_username方法,重写为只返回一个值的非参数化方法。创建与conftest.py文件中同名的non_parametrized_username方法,添加参数及返回值,重写为参数化的方法。

import pytest

@pytest.fixture
def parametrized_username():
    return 'overridden-username'

@pytest.fixture(params=['one', 'two', 'three'])
def non_parametrized_username(request):
    return request.param

def test_username(parametrized_username):
    assert parametrized_username == 'overridden-username'
    
def test_parametrized_username(non_parametrized_username):
    assert non_parametrized_username in ['one', 'two', 'three']           

在test_something_else1.py方法中不需要重写,正常调用conftest.py文件中的fixture。

def test_username(parametrized_username):
    assert parametrized_username in ['one','two','three']
    
def test_username1(non_parametrized_username):
    assert non_parametrized_username == 'username'           
D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2022.1.3\plugins\python-ce\helpers\pycharm\_jb_pytest_runner.py" --path D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests
Testing started at 12:19 ...
Launching pytest with arguments D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\tests

============================= 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 12 items

test_something.py::test_username[directly-overridden-username] PASSED    [  8%]
test_something.py::test_username_other[directly-overridden-username-other] PASSED [ 16%]
test_something1.py::test_username PASSED                                 [ 25%]
test_something1.py::test_parametrized_username[one] PASSED               [ 33%]
test_something1.py::test_parametrized_username[two] PASSED               [ 41%]
test_something1.py::test_parametrized_username[three] PASSED             [ 50%]
test_something_else.py::test_username PASSED                             [ 58%]
test_something_else1.py::test_username[one] PASSED                       [ 66%]
test_something_else1.py::test_username[two] PASSED                       [ 75%]
test_something_else1.py::test_username[three] PASSED                     [ 83%]
test_something_else1.py::test_username1 PASSED                           [ 91%]
subfolder\test_something.py::test_username PASSED                        [100%]

============================= 12 passed in 0.07s ==============================

Process finished with exit code 0
           

继续阅读