Генерация тестов py.test в python

Вопрос сначала, затем объяснение, если вам интересно.

В контексте py.test, как мне создать большой набор тестовых функций из небольшого набора шаблонов тестовых функций?

Что-то вроде:

models = [model1,model2,model3]
data_sets = [data1,data2,data3]

def generate_test_learn_parameter_function(model,data):
    def this_test(model,data):
        param = model.learn_parameters(data)
        assert((param - model.param) < 0.1 )
    return this_test

for model,data in zip(models,data_sets):
    # how can py.test can see the results of this function?
    generate_test_learn_parameter_function(model,data)

Пояснение:

Я пытаюсь успеть в модульное тестирование. Я использую код для "науки", потому что я пишу код, который, по моему мнению, сложный математически, но не так уж плохо с точки зрения программирования, т.е. У меня есть, возможно, пять функций для тестирования. То, что я родом из "науки", означает, что я довольно новичок в модульном тестировании, но был убежден, что мои друзья из CS, что это The Thing To Do.

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

Итак, если я передаю код, мне нужен один тест для каждой модели для каждой задачи. Каждый раз, когда я придумываю новую модель, мне нужно затем скопировать и вставить 5 задач, изменив структуру маринованной структуры + данные, на которые я указываю. Мне это кажется плохой. В идеале, мне нужно 5 функций шаблона, которые определяют каждую из моих 5 задач, а затем просто выплюгают тестовые функции для списка структур, которые я указываю.

Googling about приводит меня к: a) фабрикам или б) закрытию, оба из которых дополняют мой мозг и предлагают мне, что должен быть более простой способ, так как эта проблема должна регулярно возникать у правильных программистов. Так есть?


EDIT: Итак, как решить эту проблему!

def pytest_generate_tests(metafunc):
    if "model" in metafunc.funcargnames:
        models = [model1,model2,model3]
        for model in models:
            metafunc.addcall(funcargs=dict(model=model))

def test_awesome(model):
    assert model == "awesome"

Это применит тест test_awesome к каждой модели в моем списке моделей! Спасибо @dfichter!

(ПРИМЕЧАНИЕ: это утверждение всегда проходит, btw)

Ответы

Ответ 1

Хорошие инстинкты. py.test поддерживает именно то, о чем вы говорите, с помощью ловушки pytest_generate_tests(). Они объясняют это здесь.

Ответ 2

Вы также можете сделать это, используя параметризованные приборы. Хотя hooks - это API для создания плагинов для Py.test, параметризованные приборы - это обобщенный способ создания устройств, которые выводят несколько значений и генерируют для них дополнительные тестовые примеры.

Плагины предназначены для некоторых функций проекта (или пакета), а не специфические функции тестового набора, а параметризованные приспособления - это именно то, что нужно для параметризации некоторого ресурса для тестового набора (ов).

Таким образом, ваше решение можно переписать так:

@pytest.fixture(params=[model1, model2, model3])
def model(request):
    return request.param

def test_awesome(model):
    assert model == "awesome"