Pytest 基于参数生成测试 [英] Pytest Generate Tests Based on Arguments

查看:56
本文介绍了Pytest 基于参数生成测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

pytest 新手...

我在 conftest.py 中有以下内容从命令行收集团队参数,并读入 yaml 配置文件:

导入pytest导入 yamldef pytest_addoption(解析器):parser.addoption(' - 团队',行动='商店',)@pytest.fixture定义团队(请求):返回 request.config.getoption('--team')@pytest.fixture定义 conf(请求):with open('config.yml', 'r') as f:conf = yaml.load(f.read())返回配置

我想对 conf[team]['players'](一个列表)中的每个玩家进行测试.我可以在 test_players.py 中执行以下操作:

def test_players(team, conf):球员 = conf[团队]['球员']对于玩家中的 p:断言 p == 某物

这种工作,因为它遍历玩家,但整个事情被视为一个单一的测试.如果有任何失败,则整个测试被视为失败.我希望对每个玩家进行单独测试.

如果我手动放入播放器,我可以让它工作:

导入pytest类 Test_Player():@pytest.mark.parametrize('玩家', ['玩家1','玩家2','玩家 3',],)def test_player(self, player):断言玩家==某事

所以我的问题是我不知道如何将 conf[team] 传递给 pytest.mark.parametrize.我已经尝试过这些,但在这两种情况下,它都抱怨未定义 conf.

导入pytest类 Test_Player():@pytest.mark.parametrize('玩家', conf[团队]['玩家'],)def test_player(self, player):断言玩家==某事

导入pytest类 Test_Player(团队,conf):@pytest.mark.parametrize('玩家', conf[团队]['玩家'],)def test_player(self, player):断言玩家==某事

我在这里遗漏了什么?

解决方案

你设置的问题是你想在 conf[team] 上参数化,但是 conf需要在 import 时定义,因为那是装饰器执行的时候.

因此,您必须使用 pytest 的 metafunc 参数化 功能.

<预><代码>.├── conftest.py├──teams.yml└── test_bobs.py

在 yaml 文件中:

#teams.yml鲍勃:[鲍勃1,鲍勃2,土豆]保罗:[paultato]

在测试模块中:

# test_bobs.pydef test_player(玩家):在播放器中断言鲍勃"

在 pytest 配置中:

导入pytest导入 yamldef pytest_addoption(解析器):parser.addoption('--team', action='store')def pytest_generate_tests(metafunc):如果 metafunc.fixturenames 中的玩家":team_name = metafunc.config.getoption('team')# 如果你愿意,你可以把这部分移到模块范围with open('./teams.yml') as f:团队 = yaml.load(f)metafunc.parametrize("player", team.get(team_name, []))

现在执行:

pytest --team bobs

您应该看到执行了三个测试:两个通过测试(bob1、bob2)和一个失败测试(土豆).使用 pytest --team pauls 会使测试失败.使用 pytest --team bogus 将导致跳过测试.如果您想要不同的行为,请将 teams.get(team_name, []) 更改为例如 teams[team_name].

New to pytest...

I have the following in conftest.py to collect a team argument from the command line, and read in a yaml config file:

import pytest
import yaml


def pytest_addoption(parser):
    parser.addoption(
        '--team',
        action='store',
        )


@pytest.fixture
def team(request):
    return request.config.getoption('--team')


@pytest.fixture
def conf(request):
    with open('config.yml', 'r') as f:
        conf = yaml.load(f.read())
    return conf

I want to run a test on each player inside conf[team]['players'] (a list). I can do so as follows in test_players.py:

def test_players(team, conf):
    players = conf[team]['players']
    for p in players:
        assert p == something

This sort of works, in that it iterates through the players, but the whole thing gets treated as a single test. If anything fails the whole test is treated as failed. I'd like each player to be tested separately.

If I put in the players manually I can get this to work:

import pytest

class Test_Player():
    @pytest.mark.parametrize(
        'player', [
            'player1',
            'player2',
            'player3',
        ],
    )
    def test_player(self, player):
        assert player == something

So my problem is that I don't know how to get conf[team] passed into pytest.mark.parametrize. I've tried these, but in both cases it complains that conf isn't defined.

import pytest

class Test_Player():
    @pytest.mark.parametrize(
        'player', conf[team]['players'],
    )
    def test_player(self, player):
        assert player == something

and

import pytest

class Test_Player(team, conf):
    @pytest.mark.parametrize(
        'player', conf[team]['players'],
    )
    def test_player(self, player):
        assert player == something

What am I missing here?

解决方案

The problem with your setup is that you want to parameterize on conf[team], but conf needs to be defined at import time, because that's when the decorator executes.

So, you'll have to go about this parameterization differently, using pytest's metafunc parametrization features.

.
├── conftest.py
├── teams.yml
└── test_bobs.py

In the yaml file:

# teams.yml
bobs: [bob1, bob2, potato]
pauls: [paultato]

In the test module:

# test_bobs.py
def test_player(player):
    assert 'bob' in player

In the pytest conf:

import pytest
import yaml


def pytest_addoption(parser):
    parser.addoption('--team', action='store')


def pytest_generate_tests(metafunc):
    if 'player' in metafunc.fixturenames:
        team_name = metafunc.config.getoption('team')

        # you can move this part out to module scope if you want
        with open('./teams.yml') as f:
            teams = yaml.load(f)

        metafunc.parametrize("player", teams.get(team_name, []))

Now execute:

pytest --team bobs

You should see three tests executed: two passing tests (bob1, bob2) and one failing test (potato). Using pytest --team pauls will make one failing test. Using pytest --team bogus will result in a skipped test. If you want a different behaviour there, change the teams.get(team_name, []) to, for example, teams[team_name].

这篇关于Pytest 基于参数生成测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆