Тестирование одного модульного тестового примера со многими приборами / сценариями в Pytest

У меня есть класс, который представляет определенное сложное состояние. Это состояние может измениться, и у меня есть еще один экземпляр этого класса, который представляет «истинное» состояние. Я написал функцию, которая выполняет некоторую различную логику и выясняет, как привести текущее состояние в истинное состояние, если они отличаются.

Я хочу протестировать эту функцию, используя pytest. Существует множество сценариев, но логика тестирования довольно проста и сводится к (псевдокод Python):

def test_diffing(current_state, prescribed_state):
    properties_to_add = []
    properties_to_delete = []
    properties_to_modify = []
    properties_to_add, properties_to_delete, properties_to_modify = diff_logic(current_state, prescribed_state)

    assert properties_to_add == 1
    assert properties_to_delete == 0
    assert properties_to_modify == 3

Числа в правой части утверждения зависят от того, что такое current_state. У меня много current_state сценариев.

Как лучше всего написать единичный модульный тест, как указано выше, со многими парами фикстур, так что current_state передается вместе с ожидаемыми значениями утверждений?

Я рассмотрел параметризацию приспособлений pytest, но проблема с этим подходом заключается в том, что он использует декораторы и очень быстро становится уродливым *, особенно с большим количеством аргументов и большим количеством тестовых примеров. Похоже, что это не то, для чего мне следует использовать приспособления.

Как лучше всего добиться того, что я пытаюсь делать чисто?

* Я говорю, что это становится некрасиво, потому что наличие 15 или 20 наборов аргументов для декоратора очень сбивает с толку и вводит много логики в сам декоратор.


person darksky    schedule 11.07.2017    source источник
comment
Если я правильно понимаю, фикстуры больше предназначены для общности между тестами, а не для различных входных данных. В вашем случае вам, вероятно, лучше написать 15-20 модульных тестов, если вы тестируете 15-20 уникальных сценариев.   -  person Avantol13    schedule 11.07.2017
comment
В этом есть смысл. Как лучше всего избежать 15-20 повторения одной и той же логики? Единственное отличие - это объект current_state вместе с его ожиданиями.   -  person darksky    schedule 11.07.2017


Ответы (1)


Я думаю, вы можете использовать параметризованные приборы, чтобы получить то, что вы хотеть.

Как насчет чего-то вроде:

@pytest.fixture(params=[
    {
        'current_state': 'foo',
        'expected': {
            'properties_to_add': 1,
            'properties_to_delete': 2,
            'properties_to_modify': 3,
        },
    },
    ... as many scenarios as you'd like ...
])
def bundle(request):
    return request.param

@pytest.fixture
def current_state(bundle):
    return bundle['current_state']

@pytest.fixture
def expected(bundle):
    return bundle['expected']

Я использую конструкцию фиксации "bundle", чтобы связать вместе входы и выходы. Тогда тест выглядит очень чистым:

def test_diffing(current_state, expected):
    prescribed_state = ...  # I assume this is a constant, you can inject "prescribed_state" in the fixture in the same way as "current_state" and "expected"
    properties_to_add, properties_to_delete, properties_to_modify = diff_logic(current_state, prescribed_state)
    assert expected == {
        'properties_to_add': properties_to_add,
        'properties_to_delete': properties_to_delete,
        'properties_to_modify': properties_to_modify,
    }

Затем, если структура данных "params" (для фикстуры "bundle") становится очень большой, вы можете определить ее где-нибудь еще и отформатировать код для удобства чтения, загрузить его из файла данных и т. Д.

person Frank T    schedule 11.07.2017