1

我有一个使用目录中的文件作为参数的代码:

def get_testcases(directory):
    files = list(os.listdir(directory))
    testcases = filter(lambda x: x.endswith('.yaml'), files)
    for testcase in testcases:
        postconf = testcase.replace('.yaml', '.conf')
        yield (
            os.path.join(directory, testcase),
            os.path.join(directory, postconf)
        )

def get_pre_configs(directory):
    for file in os.listdir(directory):
        if file.endswith('.conf'):
            yield os.path.join(directory, file)

@pytest.mark.parametrize("pre_config", get_pre_configs('pre_configs'))
@pytest.mark.parametrize("testcase_declaration, testcase_result", get_testcases('testcases'))
def test_foo(pre_config, testcase_declaration, testcase_result):
    assert testcase_declaration
    assert testcase_result
    assert pre_config

它可以按我的需要工作,但我不喜欢 pytest 输出:

test_interface.py::test_foo[testcases/up.yaml-testcases/up.conf-pre_configs/bad.conf] PASSED              [ 16%]
test_interface.py::test_foo[testcases/up.yaml-testcases/up.conf-pre_configs/simple.conf] PASSED           [ 33%]
test_interface.py::test_foo[testcases/up.yaml-testcases/up.conf-pre_configs/complicated.conf] PASSED      [ 50%]
test_interface.py::test_foo[testcases/down.yaml-testcases/down.conf-pre_configs/bad.conf] PASSED          [ 66%]
test_interface.py::test_foo[testcases/down.yaml-testcases/down.conf-pre_configs/simple.conf] PASSED       [ 83%]
test_interface.py::test_foo[testcases/down.yaml-testcases/down.conf-pre_configs/complicated.conf] PASSED  [100%]

有没有办法为测试显示与传递给测试的值不同的名称?我想从文件名中删除目录名称和扩展名(仅用于测试名称,我想将它们“按原样”传递给测试)。

4

1 回答 1

1

事实证明@pytest.mark.parametrize(以及@pytest.fixtures)非常强大。它们允许您通过指定ids列表来更改每个测试的名称。诀窍是parametrize动态生成参数。

我重构了你的代码(见下文)。给定一个本地目录,其中包含:

$ find . -type f -name '*.yaml' -o -name '*.conf'
./pre_configs/yikes.conf
./pre_configs/foobar.conf
./testcases/hello.yaml
./testcases/world.yaml

那么pytest的输出是:

collecting ... collected 4 items

test_foo.py::test_foo[yikes-hello] PASSED                                [ 25%]
test_foo.py::test_foo[yikes-world] PASSED                                [ 50%]
test_foo.py::test_foo[foobar-hello] PASSED                               [ 75%]
test_foo.py::test_foo[foobar-world] PASSED                               [100%]

============================== 4 passed in 0.19s ===============================

这是重构的代码。请注意 bothget_testcases()get_pre_configs()both 如何返回dict可用作kwargsfor 的a @pytest.mark.parametrize。特别是,ids允许​​您覆盖pytest.

def getfiles(directory, ext):
    """return two lists: fullpath and names (without extension)"""
    n = len(ext)
    paths, names = zip(*[
        (ent.path, ent.name[:-n])
        for ent in os.scandir(directory)
        if ent.is_file() and ent.name.endswith(ext)])
    return paths, names


def get_testcases(directory):
    ypaths, names = getfiles(directory, '.yaml')
    cpaths = [f'{os.path.splitext(s)[0]}.conf' for s in ypaths]
    return {
        'argnames': ['testcase_declaration', 'testcase_result'],
        'argvalues': zip(ypaths, cpaths),
        'ids': names}


def get_pre_configs(directory):
    paths, names = getfiles(directory, '.conf')
    return {
        'argnames': ['pre_config'],
        'argvalues': zip(paths),  # always wants a list of tuples
        'ids': names}


@pytest.mark.parametrize(**get_pre_configs('pre_configs'))
@pytest.mark.parametrize(**get_testcases('testcases'))
def test_foo(pre_config, testcase_declaration, testcase_result):
    assert os.path.isfile(pre_config)
    assert os.path.isfile(testcase_declaration)
    assert testcase_result
于 2020-12-04T14:33:04.210 回答