【问题标题】:Pytest Generate Tests Based on ArgumentsPytest 基于参数生成测试
【发布时间】:2018-03-06 02:53:27
【问题描述】:

pytest 新手...

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

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

我想对 conf[team]['players'](列表)中的每个玩家进行测试。我可以在 test_players.py 中这样做:

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

这种方法很有效,因为它迭代了玩家,但整个事情都被视为一个单独的测试。如果有任何失败,整个测试将被视为失败。我希望对每个玩家进行单独测试。

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

import pytest

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

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

import pytest

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

import pytest

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

我在这里错过了什么?

【问题讨论】:

    标签: python pytest


    【解决方案1】:

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

    因此,您必须使用 pytest 的 metafunc parametrization 功能以不同的方式进行此参数化。

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

    在yaml文件中:

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

    在测试模块中:

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

    在 pytest 配置文件中:

    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, []))
    

    现在执行:

    pytest --team bobs
    

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

    【讨论】:

    • 这很有帮助,谢谢。我遇到的唯一问题是我有额外的测试不需要播放器“metafunc.parametrize”。现在我尝试运行的任何其他测试都会给出 ValueError: uses no argument 'player'
    • 基本上我希望做的是将生成的测试与其他常规测试混合在一起。
    • 您是否包含了if 'player' in metafunc.fixturenames: 部分?如果我在test_bobs.py 中添加另一个测试而不使用player 夹具,它仍然可以正常工作。请创建一个 MCVE。
    • 是的,你成功了。当我“改进”您提供的代码时,我取出了那个 if 语句。非常感谢,现在一切都按我的意愿工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-29
    • 2023-02-09
    • 2019-08-11
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多