2013-08-02 41 views
43

我正在使用py.test來測試一些封裝在python類MyTester中的DLL代碼。 爲了驗證目的,我需要在測試過程中記錄一些測試數據,然後再做更多處理。由於我有很多測試_...文件,我想在我的大多數測試中重新使用測試器對象創建(MyTester的實例)。py.test:將參數傳遞給fixture函數

由於測試者對象是獲得對DLL的變量和函數的引用的對象,所以我需要將每個測試文件的DLL變量列表傳遞給測試者對象(要記錄的變量是相同的一個測試_...文件)。 列表的內容應被用來記錄指定的數據。

我的想法是做它在某種程度上是這樣的:

import pytest 

class MyTester(): 
    def __init__(self, arg = ["var0", "var1"]): 
     self.arg = arg 
     # self.use_arg_to_init_logging_part() 

    def dothis(self): 
     print "this" 

    def dothat(self): 
     print "that" 

# located in conftest.py (because other test will reuse it) 

@pytest.fixture() 
def tester(request): 
    """ create tester object """ 
    # how to use the list below for arg? 
    _tester = MyTester() 
    return _tester 

# located in test_...py 

# @pytest.mark.usefixtures("tester") 
class TestIt(): 

    # def __init__(self): 
    #  self.args_for_tester = ["var1", "var2"] 
    #  # how to pass this list to the tester fixture? 

    def test_tc1(self, tester): 
     tester.dothis() 
     assert 0 # for demo purpose 

    def test_tc2(self, tester): 
     tester.dothat() 
     assert 0 # for demo purpose 

是否有可能實現它像這樣還是說沒有一個更優雅的方式?

通常我可以用某種設置函數(xUnit-style)爲每個測試方法做到這一點。但我想獲得某種重用。有沒有人知道這是可能的與固定裝置?

我知道我可以做這樣的事情:(從文檔)

@pytest.fixture(scope="module", params=["merlinux.eu", "mail.python.org"]) 

但我需要直接的參數化測試模塊中。 是否可以從測試模塊訪問燈具的參數屬性?

回答

45

我有一個類似的問題 - 我有一個名爲test_package的夾具,後來我想在特定的測試中運行該夾具時可以將可選參數傳遞給該夾具。例如:

@pytest.fixture() 
def test_package(request, version='1.0'): 
    ... 
    request.addfinalizer(fin) 
    ... 
    return package 

(這不要緊,這些目的是什麼呢夾具或什麼類型的對象返回package的)是。

然後希望以某種方式在測試功能中使用此燈具,以便我也可以指定該燈具的參數version用於該測試。目前這是不可能的,雖然可能會成爲一個不錯的功能。

在此期間很容易足以讓我的燈具簡單地返回一個功能,做燈具之前所做的所有工作,但可以讓我指定version參數:

@pytest.fixture() 
def test_package(request): 
    def make_test_package(version='1.0'): 
     ... 
     request.addfinalizer(fin) 
     ... 
     return test_package 

    return make_test_package 

現在我可以

def test_install_package(test_package): 
    package = test_package(version='1.1') 
    ... 
    assert ... 

等:像我的測試功能,使用此功能。

的OP的嘗試性解決方案是朝着正確的方向,如@ hpk42的answer所暗示的,MyTester.__init__可能只是存儲過像要求一個參考:

class MyTester(object): 
    def __init__(self, request, arg=["var0", "var1"]): 
     self.request = request 
     self.arg = arg 
     # self.use_arg_to_init_logging_part() 

    def dothis(self): 
     print "this" 

    def dothat(self): 
     print "that" 

然後用這個來實現類似的燈具:

@pytest.fixture() 
def tester(request): 
    """ create tester object """ 
    # how to use the list below for arg? 
    _tester = MyTester(request) 
    return _tester 

如果需要,MyTester類可能被重組了一點,所以,它已被創建後其.args屬性可以被更新,以調整爲individ行爲ual測試。

+0

感謝提示夾具內的功能。花了一些時間,直到我可以再次工作,但這是非常有用的! – maggie

10

您可以從夾具功能(因此從您的測試儀類)訪問請求模塊/類/功能,請參閱interacting with requesting test context from a fixture function。所以你可以在一個類或模塊上聲明一些參數,測試儀夾具可以檢測它。

+3

我知道我可以做這樣的事情:(從文檔)@ pytest.fixture(範圍= 「模塊」, PARAMS =「merlinux。歐盟「,」mail.python.org「]) 但我需要在測試模塊中做到這一點。我怎樣才能動態地添加PARAMS到燈具? – maggie

+1

重點不是必須與請求測試上下文*進行交互,而是要有一個定義明確的方法來將參數傳遞給fixture函數。 Fixture函數不需要知道請求測試上下文的類型,只是爲了能夠接收帶有商定名稱的參數。例如,我們希望能夠編寫'@fixture def my_fixture(request)',然後'@pass_args(arg1 = ...,arg2 = ...)def test(my_fixture)',並將這些參數寫入'my_fixture ()'像這樣'arg1 = request.arg1,arg2 = request.arg2'。現在在py.test中可以這樣做嗎? –

61

這實際上是通過indirect parametrization在py.test中本地支持的。

在你的情況,你會:

@pytest.fixture 
def tester(request): 
    """Create tester object""" 
    return MyTester(request.param) 


class TestIt: 
    @pytest.mark.parametrize('tester', [['var1', 'var2']], indirect=True) 
    def test_tc1(self, tester): 
     tester.dothis() 
     assert 1 
+0

啊,這很不錯(我認爲你的例子可能有點過時了 - 它不同於官方文檔中的例子)。這是一個相對較新的功能嗎?我從來沒有遇到過它。這也是一個很好的解決方案 - 在某些方面比我的答案更好。 – Iguananaut

+0

我嘗試過使用此解決方案,但遇到了傳遞多個參數或使用請求以外的變量名稱的問題。我最終使用@Iguananaut的解決方案。 –

+14

**這應該是公認的答案。** [官方文檔](http://docs.pytest.org/en/latest/example/parametrize.html#deferring-the-setup-of-parametrized-resources)因爲「間接」關鍵字參數被認爲是稀疏和不友好的,這可能說明了這種基本技術的模糊性。我已經多次爲py.test網站搜索這個功能 - 只是出現空洞,老舊和混亂。苦味是一個被稱爲持續整合的地方。 _Thank Odin for Stackoverflow._ –