我需要创建多个用户(通过发送HTTP请求),并使用创建的用户数据(登录、密码)运行登录页面测试

我有Fixture,它生成用户并提供他们的登录数据(Year中的元组列表,如[(login1,password1),(login2,password2)].我想使用这个成品率数据作为参数,因为我只知道用不同的测试数据多次运行一个测试的一种正确方法.

以下是代码:

conftest.py

@pytest.fixture(scope="session", autouse=True)
def test_user_fixture():
    print("INFO | Generating test user data")
    user_data_set = user_data_generator()
    login_data = []

    for user_data in user_data_set:
        login_data.append((user_data[0], user_data[1]))
        if send_user_create_request(user_data) != 200: # this function sends request to create user AND returns status_code
            pytest.exit("ERROR | Test user wasn't created")

    yield login_data

    print("INFO | Clearing test data")

test_login_page.py

@pytest.mark.usefixtures('webdriver_fixture', 'test_user_fixture')
class TestPositiveLogin:

    @pytest.mark.parametrize("login, password", test_user_fixture)
    def test_positive_login(self, webdriver_fixture, login, password):
        driver = webdriver_fixture
        page = BasePage(driver)
        page.open_base_page()
        page.login(login, password)

在这里,我try 只使用fuxture作为参数,因为LOGIN_DATA非常适合参数数据格式,但是Python说

NameError:未定义名称‘TEST_USER_Fixture’

你能帮我解决这个问题吗?或许你能给我另一个解决方案

推荐答案

您当前的test_user_fixture装置将返回一个登录/密码列表.我确信您正在使用yield,因为您希望稍后进行一些清理(例如,删除用户).

我的建议是让test_user_fixture只返回一个登录/密码.然后,我们可以使用关键字params=对该灯具进行参数化:

# conftest.py
import logging

import pytest

def user_data_generator():
    """Mocked"""
    return [
        ("user1", "password1"),
        ("user2", "password2"),
    ]

USERS_DATA = list(user_data_generator())

def test_id(user_data):
    """Given (login, password), return the login part.

    We use this login as part of the test ID
    """
    return user_data[0]


@pytest.fixture(scope="session", autouse=True, params=USERS_DATA, ids=test_id)
def test_user_fixture(request):
    login, password = request.param[:2]
    logging.debug("In test_user_fixture, login=%r, password=%r", login, password)

    if send_user_create_request((login, password)) != 200:
        pytest.exit("ERROR | Test user wasn't created")
    yield login, password

    logging.info("Clearing test data")

# test_login_page.py
import logging


class TestPositiveLogin:
    def test_positive_login(self, webdriver_fixture, test_user_fixture):
        login, password = test_user_fixture
        logging.debug("webdriver_fixture=%r", webdriver_fixture)
        logging.debug("login=%r", login)
        logging.debug("password=%r", password)

# pyproject.toml
[tool.pytest.ini_options]
log_cli="true"
log_level="DEBUG"

log_cli="false"时的输出:

test_login_page.py::TestPositiveLogin::test_positive_login[user1] PASSED
test_login_page.py::TestPositiveLogin::test_positive_login[user2] PASSED

log_cli="true"时的输出:


test_login_page.py::TestPositiveLogin::test_positive_login[user1]
---------------------------------------------------------------------- live log setup ----------------------------------------------------------------------
DEBUG    root:conftest.py:26 In test_user_fixture, login='user1', password='password1'
---------------------------------------------------------------------- live log call -----------------------------------------------------------------------
DEBUG    root:test_login_page.py:8 webdriver_fixture='Mocked WebDriver'
DEBUG    root:test_login_page.py:9 login='user1'
DEBUG    root:test_login_page.py:10 password='password1'
PASSED
test_login_page.py::TestPositiveLogin::test_positive_login[user2]
---------------------------------------------------------------------- live log setup ----------------------------------------------------------------------
INFO     root:conftest.py:32 Clearing test data for login='user1'
DEBUG    root:conftest.py:26 In test_user_fixture, login='user2', password='password2'
---------------------------------------------------------------------- live log call -----------------------------------------------------------------------
DEBUG    root:test_login_page.py:8 webdriver_fixture='Mocked WebDriver'
DEBUG    root:test_login_page.py:9 login='user2'
DEBUG    root:test_login_page.py:10 password='password2'
PASSED
-------------------------------------------------------------------- live log teardown ---------------------------------------------------------------------
INFO     root:conftest.py:32 Clearing test data for login='user2'

备注

  • 假设USERS_DATA包含[(user, password, ...), ...]

  • params=USERS_DATA个人将灯具参数化.即使该装置的作用域是会话级别的,它也将为USERS_DATA中的每个元素调用一次.换句话说,如果USERS_DATA包含2个元素,则该装置将被调用两次.

  • test_id()函数从测试参数中提取login,从而提供了一种更好地识别测试的方法.

  • test_user_fixture返回(login, password)的元组,因此在测试中,我们将其解包以使其更容易:

      login, password = test_user_fixture
    
  • 我更喜欢用logging而不是print,因为我可以通过这条线路打开/关闭pyproject.toml:

      log_cli="true"
    

    just replace true with false 和 I can effectively turn off all logging. I can also control the log level (e.g. WARN, INFO, DEBUG, ...) with this line:

      log_level="DEBUG"
    

Update

如果go 掉ids=部分,则输出将如下所示:

test_login_page.py::TestPositiveLogin::test_positive_login[test_user_fixture0] PASSED
test_login_page.py::TestPositiveLogin::test_positive_login[test_user_fixture1] PASSED

Notice the part inside the square brackets test_user_fixture0test_user_fixture1: they are IDs which pytest generate automatically 和 they are not helpful.

我想要放在这些方括号中的是ID,它们很有用,比如login.

根据pytest doc的说法,ids=可能是一系列ID.这意味着以下内容的工作方式相同:

USERS_DATA = list(user_data_generator())
TEST_IDS = [user_data[0] for user_data in USERS_DATA]
@pytest.fixture(
    scope="session",
    autouse=True,
    params=USERS_DATA,
    ids=TEST_IDS,
)
def test_user_fixture(request):
    ...

例如,如果USERS_DATA

[
    ("user1", "password1"),
    ("user2", "password2"),
]

那么,TEST_IDS美元将是

[
    "user1",
    "user2",
]

And these IDs will be used inside of the square brackets. Note that the ids= can also be a function which take in a single element of the params= parameter 和 return an ID. In this case we have:

USERS_DATA = list(user_data_generator())
def test_id(user_data):
    # Example of user_data: ("user1", "password1")
    return user_data[0]

@pytest.fixture(
    scope="session",
    autouse=True,
    params=USERS_DATA,
    ids=test_id,
)
def test_user_fixture(request):
    ...

That means pytest will pass each element in USERS_DATA into the function test_id 和 use the return value as the ID.

Which method should we use? I believe the first method with TEST_IDS are easier to underst和. The second method is more powerful 和 that is what I use in my projects.

Python相关问答推荐

Polars比较了两个预设-有没有方法在第一次不匹配时立即失败

Pytest两个具有无限循环和await命令的Deliverc函数

用合并列替换现有列并重命名

在Python中管理打开对话框

如何从在虚拟Python环境中运行的脚本中运行需要宿主Python环境的Shell脚本?

Pandas—合并数据帧,在公共列上保留非空值,在另一列上保留平均值

pyscript中的压痕问题

如何使用Python以编程方式判断和检索Angular网站的动态内容?

如何使Matplotlib标题以图形为中心,而图例框则以图形为中心

在单个对象中解析多个Python数据帧

如何使用两个关键函数来排序一个多索引框架?

matplotlib + python foor loop

在Google Drive中获取特定文件夹内的FolderID和文件夹名称

为什么t sns.barplot图例不显示所有值?'

在Python中控制列表中的数据步长

如何在Python中自动创建数字文件夹和正在进行的文件夹?

对于数组中的所有元素,Pandas SELECT行都具有值

Match-Case构造中的对象可调用性测试

401使用有效的OAuth令牌向Google Apps脚本Web App发出POST请求时出现未经授权的错误(";

从`end_date`回溯,如何计算以极为单位的滚动统计量?