1 回答

TA貢獻(xiàn)1820條經(jīng)驗(yàn) 獲得超3個贊
我不是 100% 確定我理解你在這里試圖做什么,但我認(rèn)為你對參數(shù)化和固定裝置作用的理解是不正確的??雌饋砟趪L試使用固定裝置為您的測試創(chuàng)建參數(shù)列表,這并不是真正正確的方法(而且您這樣做的方式肯定行不通,正如您所看到的) .
為了全面解釋如何解決這個問題,首先,讓我介紹一下參數(shù)化和固定裝置的使用背景。
參數(shù)化
我不認(rèn)為這里有任何新內(nèi)容,只是為了確保我們在同一頁面上:
通常,在 Pytest 中,一個test_*函數(shù)就是一個測試用例:
def test_square():
assert square(3) == 9
如果你想做相同的測試但使用不同的數(shù)據(jù),你可以編寫單獨(dú)的測試:
def test_square_pos():
assert square(3) == 9
def test_square_frac():
assert square(0.5) == 0.25
def test_square_zero():
assert square(0) == 0
def test_square_neg():
assert square(-3) == 9
這不是很好,因?yàn)樗`反了DRY原則。參數(shù)化是解決這個問題的方法。您可以通過提供測試參數(shù)列表將一個測試用例變成多個:
@pytest.mark.parametrize('test_input,expected',
[(3, 9), (0.5, 0.25), (0, 0), (-3, 9)])
def test_square(test_input, expected):
assert square(test_input) == expected
固定裝置
Fixture 也與DRY代碼有關(guān),但方式不同。
假設(shè)您正在編寫一個 Web 應(yīng)用程序。您可能有多個測試需要連接到數(shù)據(jù)庫。您可以向每個測試添加相同的代碼以打開和設(shè)置測試數(shù)據(jù)庫,但這肯定是在重復(fù)您自己。比方說,如果您切換數(shù)據(jù)庫,則需要更新大量測試代碼。
夾具是允許您進(jìn)行一些可用于多個測試的設(shè)置(以及可能的拆卸)的功能:
@pytest.fixture
def db_connection():
# Open a temporary database in memory
db = sqlite3.connect(':memory:')
# Create a table of test orders to use
db.execute('CREATE TABLE orders (id, customer, item)')
db.executemany('INSERT INTO orders (id, customer, item) VALUES (?, ?, ?)',
[(1, 'Max', 'Pens'),
(2, 'Rachel', 'Binders'),
(3, 'Max', 'White out'),
(4, 'Alice', 'Highlighters')])
return db
def test_get_orders_by_name(db_connection):
orders = get_orders_by_name(db_connection, 'Max')
assert orders = [(1, 'Max', 'Pens'),
(3, 'Max', 'White out')]
def test_get_orders_by_name_nonexistent(db_connection):
orders = get_orders_by_name(db_connection, 'John')
assert orders = []
修正你的代碼
好的,在了解了背景知識后,讓我們深入研究您的代碼。
第一個問題是你的@pytest.mark.parametrize裝飾器:
@pytest.mark.parametrize("get_fus_output", [test_input_df, test_truth_df, res_path], indirect=True)
這不是使用indirect. 就像測試可以參數(shù)化一樣,夾具也可以參數(shù)化。從文檔中看不是很清楚(在我看來),但這indirect只是參數(shù)化固定裝置的另一種方法。這與在另一個 fixture 中使用 fixture完全不同,這正是您想要的。
事實(shí)上,要get_fus_output使用test_input_df、test_truth_df和fixtures,您根本res_path不需要這條線。通常,如果沒有以其他方式使用(例如,由裝飾器),@pytest.mark.parametrize測試函數(shù)或夾具的任何參數(shù)都會自動假定為夾具。@pytest.mark.parametrize
所以,你現(xiàn)有的@pytest.mark.parametrize并沒有按照你的期望去做。那么你如何參數(shù)化你的測試呢?這會遇到更大的問題:您正在嘗試使用get_fus_output夾具為 . 創(chuàng)建參數(shù)test_annotation_match。這不是你可以用夾具做的事情。
Pytest運(yùn)行時,首先收集所有的測試用例,然后一個一個運(yùn)行。測試參數(shù)必須在收集階段準(zhǔn)備就緒,但 fixture 直到測試階段才會運(yùn)行。夾具內(nèi)的代碼無法幫助進(jìn)行參數(shù)化。您仍然可以通過編程方式生成參數(shù),但固定裝置不是這樣做的方法。
你需要做幾件事:
首先,將get_fus_output夾具轉(zhuǎn)換為常規(guī)函數(shù)。這意味著刪除@pytest.fixture裝飾器,但您還必須更新它以不使用test_input_df test_truth_df, 和res_path固定裝置。(如果沒有其他東西需要它們作為固定裝置,您可以將它們?nèi)哭D(zhuǎn)換為常規(guī)函數(shù),在這種情況下,您可能希望將它們放在它們自己的模塊之外,或者只是將它們移動到同一個測試腳本中。conftest.py)
然后,@pytest.mark.parametrize需要使用該函數(shù)來獲取參數(shù)列表:
@pytest.mark.parametrize("expected,test", get_fus_output())
def test_annotation_match(expected, test):
assert_frame_equal(test, expected, check_dtype=False, check_like=True)
添加回答
舉報