2011-02-07 3 views
15

Вопрос сначала, затем объяснение, если вам интересно.генерация тестов 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!

(Примечание: что утверждают всегда проходит, кстати)

+0

Вообще это плохая идея для создания тестового кода динамически, как это. Потому что тогда вам нужно написать тесты для тестового кода и т. Д. 'Копировать и вставлять 5 задач', я думаю, это показывает, что вместо генерации нового кода или копирования вставки вы можете найти общие черты, которые могут выполнять ваши функции, не зная точно, что они повторное тестирование. – Falmarri

+2

На данный момент я пишу тесты, которые выглядят как def test_learn: для модели в моделях: assert (error

+1

@Falmarri: http://en.wikipedia.org/wiki/Copy_and_paste_programming Пожалуйста, избегайте его почти во всех случаях. – lpapp

ответ

15

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

+0

Это потрясающе. Я отредактирую свой вопрос, чтобы добавить то, что я сделал в конце, на случай, если кто-нибудь придет сюда искать похожие вещи. –

+0

dfichter, не могли бы вы также привести пример в OP? – lpapp

+0

Ссылка сейчас –

4

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

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

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

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

def test_awesome(model): 
    assert model == "awesome" 
Смежные вопросы