3

テストでボイラープレートを繰り返しすぎないようにしています。より構造化された方法で書き直したいと考えています。2 つの異なるパーサーがあり、どちらもテキストを解析してdoc. そのドキュメントは、他のテストで使用されます。最終的な目標は、他のテストで使用できるフィクスチャを公開することです。doc()フィクスチャは、指定されたパーサーとテキストのすべての組み合わせを実行するようにパラメーター化されます。

@pytest.fixture
def parser_a():
    return "parser_a"  # actually a parser object

@pytest.fixture
def parser_b():
    return "parser_b"  # actually a parser object

@pytest.fixture
def short_text():
    return "Lorem ipsum"

@pytest.fixture
def long_text():
    return "If I only knew how to bake cookies I could make everyone happy."

doc()問題は、次のようなフィクスチャを作成する方法です。

@pytest.fixture(params=???)
def doc(parser, text):
    return parser.parse(text)

ここで、parserは parser_a と parser_b、および short_text と long_text になるようにパラメーター化されていますtext。これはdoc、パーサーとテキストの合計 4 つの組み合わせをテストすることを意味します。

PyTest のパラメーター化されたフィクスチャに関するドキュメントは非常に曖昧であり、これにアプローチする方法についての答えが見つかりませんでした。すべてのヘルプ歓迎。

4

2 に答える 2

1

これがまさに必要なものかどうかはわかりませんが、フィクスチャの代わりに関数を使用して、フィクスチャでこれらを組み合わせることができます。

import pytest

class Parser:  # dummy parser for testing
    def __init__(self, name):
        self.name = name

    def parse(self, text):
        return f'{self.name}({text})'


class ParserFactory:  # do not recreate existing parsers
    parsers = {}

    @classmethod
    def instance(cls, name):
        if name not in cls.parsers:
            cls.parsers[name] = Parser(name)
        return cls.parsers[name]

def parser_a():
    return ParserFactory.instance("parser_a") 

def parser_b():
    return ParserFactory.instance("parser_b")

def short_text():
    return "Lorem ipsum"

def long_text():
    return "If I only knew how to bake cookies I could make everyone happy."


@pytest.fixture(params=[long_text, short_text])
def text(request):
    yield request.param

@pytest.fixture(params=[parser_a, parser_b])
def parser(request):
    yield request.param

@pytest.fixture
def doc(parser, text):
    yield parser().parse(text())

def test_doc(doc):
    print(doc)

結果の pytest 出力は次のとおりです。

============================= test session starts =============================
...
collecting ... collected 4 items

test_combine_fixt.py::test_doc[parser_a-long_text] PASSED                [ 25%]parser_a(If I only knew how to bake cookies I could make everyone happy.)

test_combine_fixt.py::test_doc[parser_a-short_text] PASSED               [ 50%]parser_a(Lorem ipsum)

test_combine_fixt.py::test_doc[parser_b-long_text] PASSED                [ 75%]parser_b(If I only knew how to bake cookies I could make everyone happy.)

test_combine_fixt.py::test_doc[parser_b-short_text] PASSED               [100%]parser_b(Lorem ipsum)


============================== 4 passed in 0.05s ==============================

更新: 例としてコメントで説明されているように、パーサーのシングルトン ファクトリを追加しました。

注:pytest.lazy_fixture @hoefling の提案に従って 使用しようとしました。これは機能し、パーサーとテキストをフィクスチャから直接渡すことができますが、各パーサーが 1 回だけインスタンス化されるように (まだ) 機能させることはできませんでした。参考までに、使用する場合の変更されたコードは次のpytest.lazy_fixtureとおりです。

@pytest.fixture
def parser_a():
    return Parser("parser_a")

@pytest.fixture
def parser_b():
    return Parser("parser_b")

@pytest.fixture
def short_text():
    return "Lorem ipsum"

@pytest.fixture
def long_text():
    return "If I only knew how to bake cookies I could make everyone happy."


@pytest.fixture(params=[pytest.lazy_fixture('long_text'),
                        pytest.lazy_fixture('short_text')])
def text(request):
    yield request.param

@pytest.fixture(params=[pytest.lazy_fixture('parser_a'),
                        pytest.lazy_fixture('parser_b')])
def parser(request):
    yield request.param


@pytest.fixture
def doc(parser, text):
    yield parser.parse(text)


def test_doc(doc):
    print(doc)
于 2020-04-28T18:01:47.823 に答える