Pytest“run-around-tests”夹具在一个类中的所有测试之前只运行一次

Posted

技术标签:

【中文标题】Pytest“run-around-tests”夹具在一个类中的所有测试之前只运行一次【英文标题】:Pytest "run-around-tests" fixture to run only once before all tests in a class 【发布时间】:2018-10-13 12:57:52 【问题描述】:

我正在使用 pytest + selenium 测试 Web 解决方案的用户消息功能。测试将为测试用户生成一条测试消息,然后登录该用户以验证该消息确实为该用户显示。

我需要通过内部 API 生成这些消息。 为了能够访问此 API,我首先必须通过不同的 API 生成一个 AUTH 令牌。

所以测试场景基本是:

    在测试启动时,通过 API 帮助函数生成新的 AUTH 令牌。 向另一个 API 发送请求以设置新消息(需要 AUTH 令牌) 向另一个 API 发送请求以将此消息“映射”到指定用户(需要 AUTH 令牌) 登录测试用户并验证新消息确实正在显示。

我的问题是,我想避免每次运行我的测试类中的每个测试时都创建一个新的 AUTH 令牌 - 一旦所有测试在同一个测试运行中使用,我想创建一个新令牌。

在调用所有测试时生成一个新访问令牌的最聪明的解决方案是什么?

现在我想出了这样的东西,每次运行任何单独的测试时都会生成一个新令牌:

import pytest
import helpers.api_access_token_helper as token_helper
import helpers.user_message_generator_api_helper as message_helper
import helpers.login_helper as login_helper
import helpers.popup_helper as popup_helper

class TestStuff(object):

    @pytest.yield_fixture(autouse=True)
    def run_around_tests(self):
        yield token_helper.get_api_access_token()

    def test_one(self, run_around_tests):
        auth_token = run_around_tests
        message_helper.create_new_message(auth_token, some_message_data)
        message_helper.map_message_to_user(auth_token, user_one["user_id"])
        login_helper.log_in_user(user_one["user_name"], user_one["user_password"])
        assert popup_helper.user_message_is_displaying(some_message_data["title"])

    def test_two(self, run_around_tests):
        auth_token = run_around_tests
        message_helper.create_new_message(auth_token, some_other_message_data)
        message_helper.map_message_to_user(auth_token, user_two["user_id"])
        login_helper.log_in_user(user_two["user_name"], user_two["user_password"])
        assert popup_helper.user_message_is_displaying(some_other_message_data["title"])

我已经用“run-around-tests”夹具来回进行了一些实验,但还没有找到解决方案。

【问题讨论】:

【参考方案1】:

您必须调整夹具范围以缓存测试运行中的所有测试 (scope='session')、模块中的所有测试 (scope='module')、类中的所有测试(仅限旧的 unittest 样式测试)的结果, scope='class'),或用于单个测试(scope='function';这是默认测试)。例子:

夹具功能

@pytest.fixture(scope='session')
def token():
    return token_helper.get_api_access_token()


class Tests(object):

    def test_one(self, token):
        ...

    def test_two(self, token):
        ...


class OtherTests(object):

    def test_one(self, token):
        ...

令牌将在首次请求时计算一次,并在整个测试运行期间保存在缓存中,因此所有三个测试 Tests::test_oneTests::test_twoOtherTests::test_one 将共享相同的令牌值。

夹具类方法

如果您打算编写旧式测试类而不是测试函数并希望夹具成为类方法(就像它在您的代码中一样),请注意您只能使用 class 范围,以便夹具值仅在类中的测试之间共享:

class TestStuff(object):

    @pytest.fixture(scope='class')
    def token(self):
        return token_helper.get_api_access_token()

    def test_one(self, token):
        ...

    def test_two(self, token):
        ...

废话:

    pytest.yield_fixture 已弃用并由 pytest.fixture 取代; 您不需要设置autouse=True,因为您在测试参数中明确请求了夹具。无论如何都会调用它。

【讨论】:

是的,成功了。应该在夹具上多花点功夫……谢谢!【参考方案2】:

您可以将 scope="module" 参数添加到 @pytest.fixture。

根据pytest documentation:

需要网络访问的设备取决于连接性,并且是 通常创建时间昂贵。扩展前面的例子,我们 可以在 @pytest.fixture 调用中添加一个 scope="module" 参数 引起一个 smtp_connection 夹具函数,负责创建一个 连接到预先存在的 SMTP 服务器,每次只能调用一次 测试模块(默认是每个测试函数调用一次)。 因此,一个测试模块中的多个测试函数将分别接收 相同的 smtp_connection 夹具实例,从而节省时间。可能的 范围的值是:函数、类、模块、包或会话。

# content of conftest.py
import pytest
import smtplib


@pytest.fixture(scope="module")
def smtp_connection():
    return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)

夹具范围

fixture 在测试首次请求时创建,并根据它们的作用域被销毁:*

function:默认作用域,fixture在测试结束时销毁。

class: 夹具在类中最后一个测试的拆卸过程中被销毁。

module: 夹具在模块中最后一个测试的拆卸过程中被破坏。

package: 在拆解包中的最后一个测试时,fixture 被销毁。

session:夹具在测试会话结束时被销毁。

注意:Pytest 一次只缓存一个夹具实例,这意味着当使用参数化夹具时,pytest 可能会在给定范围内多次调用夹具。

【讨论】:

以上是关于Pytest“run-around-tests”夹具在一个类中的所有测试之前只运行一次的主要内容,如果未能解决你的问题,请参考以下文章

M2E 并将 maven 生成的源文件夹作为 eclipse 源文件夹

powershell Windows Phone无法用资料夹来区分影片,因此只能够用档名。而档名通常没有到资料夹层级。因此,这个Powershell脚本用资料夹前2个字元(通常表示那个章节)加上本身档

Android文件基本操作(创建文件(夹)复制文件(夹)设置文件访问权限)

源文件夹和(普通)文件夹之间有什么区别

pytest 配置文件

Python - pytest