带有树状数据的pytest嵌套参数化

pytest nested parametrization with tree-like data

使用 pytest,我正在尝试测试树状分层场景。 让我们以文档结构为例:

Document --- Chapter --- Paragraph
       1   n        1   n

文档包含多个章节;一章包含多个段落。

开始测试新文档时,一些设置代码需要运行;当开始新的章节时,一些其他的设置代码需要运行;段落也一样。

写成伪代码:

for doc in documents:
    setup_doc(doc)
    for chapter in doc.chapters:
        setup_chapter(chapter)
        for paragraph in chapter.paragraphs:
            setup_paragraph(paragraph)
            test_it(doc, chapter, paragraph)
            teardown_paragraph(paragraph)
        teardown_chapter(chapter)
    teardown_doc(doc)

如果我们有以下数据:

Document Alpha
   chapter A
      Paragraph A1
      Paragraph A2
   chapter B
      Paragraph B1

我希望收集的测试用例是:

test_it[Alpha, A, A1]
test_it[Alpha, A, A2]
test_it[Alpha, B, B1]

我尝试了 pytest_generate_tests、class 场景、固定装置和参数化测试函数的不同组合,但未能实现。

任何指点将不胜感激。

Pytest fixutes 应该是独立的。 因此,要解决您的任务,您必须构建一个包含所有功能组合(文档 - 章节 - 段落)的简单列表的夹具。

您可以使用 returns 此类列表中的一个元素的简单装置来完成此操作,或者您可以在测试生成阶段生成此列表,如下面的代码所示。

documents = {
        'Alpha': {
            'A': {'A1': {},'A2': {}},
            'B': {'B1': {}}
        }
    }


def pytest_generate_tests(metafunc):
    """Documents tree from documents"""
    if 'document' in metafunc.fixturenames:
        documents_plain = []
        for document in documents.keys():
            for chapter in documents[document].keys():
                for paragraph in documents[document][chapter].keys():
                    documents_plain.append({'document': document, 'chapter': chapter, 'paragraph': paragraph})
        metafunc.parametrize(
            'document',
            documents_plain,
            scope='session')


def test_it(document):
    print('{}, {}, {}'.format(document['document'], document['chapter'], document['paragraph']))


py.test -s

Alpha, B, B1
Alpha, A, A1
Alpha, A, A2

如果像我一样,您希望一些测试由 document 参数化,一些由 documentchapter 参数化,还有一些由 documentchapter 参数化,paragraph我的方法(受安德烈·索罗金启发)如下

conftest.py

import pytest

documents = {
    'Alpha': {
        'A': {'A1': {},'A2': {}},
        'B': {'B1': {}}
    }
}

def pytest_generate_tests(metafunc):
    if 'document' in metafunc.fixturenames:
        if 'chapter' in metafunc.fixturenames:
            if 'paragraph' in metafunc.fixturenames:
                metafunc.parametrize(
                    ['document', 'chapter', 'paragraph'],
                    [(d, c, p) for d, cs in documents.items()
                               for c, ps in cs.items()
                               for p in ps.keys()
                    ])
            else:
                metafunc.parametrize(
                    ['document', 'chapter'],
                    [(d, c) for d, cs in documents.items()
                            for c in cs.keys()
                    ])
        else:
            metafunc.parametrize(
                    'document', documents.keys())

然后在test.py

def test_d(document):
    print(document)

def test_dc(document, chapter):
    print(document, chapter)

def test_dcp(document, chapter, paragraph):
    print(document, chapter, paragraph)

运行

>>> pytest test.py -s
test.py Alpha
.Alpha A
.Alpha B
.Alpha A A2
.Alpha A A1
.Alpha B B1
.