2011-02-07 95 views
15

先問題,然後解釋一下是否有興趣。在python中生成py.test測試

在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夥伴確信它是「事情要做」。

我正在寫的代碼需要一個模型結構,一些數據,並學習模型的參數。所以我的單元測試包括一堆模型結構和預先生成的數據集,然後在每個結構+數據上完成一組約5個機器學習任務。

因此,如果我手工編寫代碼,我需要爲每個任務的每個模型測試一次。每次我想出一個新模型時,我需要複製並粘貼5個任務,更改我指向的哪個pickled結構+數據。這對我來說感覺像是不好的練習。理想情況是我想要的是5個模板函數,它們定義了我的5個任務中的每一個,然後爲我指定的結構列表吐出測試函數。

使用Google搜索將我帶到a)工廠或b)關閉,這兩者都會讓我的大腦更加生動,並且暗示我必須有一個更簡單的方法,因爲這個問題必須由合適的程序員經常面對。那麼在那裏?


編輯:所以這裏是如何解決這個問題!

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(錯誤<閾值)。但是這意味着測試可能會在任何一個模型上失敗,而我希望有一個測試失敗了一個模型和另一個模型的單獨測試,即使它是相同的機器學習函數。 –

+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是一個爲Py.test構建插件的API,但參數化的fixture是一種通用的方法,可以生成一個輸出多個值併爲其生成額外測試用例的fixture。

插件意味着某些項目範圍(或包範圍)的功能,而不是測試用例特定的功能和參數化的固件正是爲測試用例參數化某些資源所需的。

所以您的解決方案可以改寫爲:

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

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