分享一個關於在pytest中,如何將測試用例檔案中的變數傳遞到fixture函式。
一、交代應用場景
- 目前組內的專案,在根目錄下是有一個
conftest.py
檔案的,這裡有個生成api token
的fixture函式,就叫它gen_token()
吧。 - 每個case包下,也會有個
conftest.py
,用於存放適用於本模組下測試用例的fixture
函式,比如有個叫setup_before()
。 - 因為拿token是請求介面的前提,所以在case裡,比如有個
test_case()
裡,要傳頂層的fixture函式,也就是這樣test_case(gen_token)
。 - 頂層的
gen_token()
,是需要3個傳參的。因為不同case可能涉及到的生成不同使用者的token,所以我們把這個引數放在了case檔案裡。
ok,大背景是這樣的。
現在有小夥伴來需求了,她要在setup_before()
裡去造數,通過請求另一個介面,這個請求也需要使用token。
那麼,問題也就可以轉化為:
- 要將case檔案裡的引數,傳遞到fixture函式中。
- gen_token()裡返回的值,setup_before()和test_case()裡都要拿到。
二、使用@pytest.mark.parametrize、以及fixture的呼叫來解決
這裡把實際程式碼抽象一下,轉化為簡易程式碼,方便演示和理解:
# 目錄結構
-- /demo_top
-- /demo_sub
__init__.py
conftest.py
test_case.py
__init__.py
conftest.py
以下分別是/demo_top/conftest.py
、/demo_top/demo_sub/conftest.py
、/demo_top/demo_sub/test_case.py
的內容。
1. /demo_top/conftest.py
# content of /demo_top/conftest.py
import pytest
@pytest.fixture()
def gen_token(request):
params = request.param
print("\n根目錄下gen_token()拿到的引數:", params)
if params[0] + params[1] == 5:
return "api_token"
else:
return None
這裡,模擬生成token的fixture函式,當傳過來的值相加等於5,就會返回"api_token"
,否則返回None
。
2. /demo_top/demo_sub/conftest.py
# content of /demo_top/demo_sub/conftest.py
import pytest
@pytest.fixture()
def setup_before(request, gen_token):
print("執行子級setup_before,拿到的傳參:", request.param)
print("執行子級setup_before,拿到gen_token的返回值:", gen_token)
if gen_token:
yield "造數完成"
print("測試用例test_case執行完畢,清理測試資料")
else:
pytest.skip("跳過")
這裡模擬了給測試用例造資料的fixture函式,如果沒拿到token的話,就跳過測試用例。
3. /demo_top/demo_sub/test_case.py
# content of /demo_top/demo_sub/test_case.py
import pytest
test_param = [(1, 4)]
@pytest.mark.parametrize("gen_token", test_param, indirect=True)
@pytest.mark.parametrize("setup_before", test_param, indirect=True)
def test_case1(gen_token, setup_before):
print("\n測試用例裡拿到的gen_token返回值:", gen_token)
print("測試用例裡拿到的setup_before返回值:", setup_before)
print("執行測試用例test_case1...")
if __name__ == '__main__':
pytest.main(['-s', 'test_case.py'])
這是測試用例檔案了,裡面有個測試函式test_case1
,因為它需要用到2個fixture函式返回的值,所以gen_token, setup_before
都請求。
引數傳遞
- @pytest.mark.parametrize:使用pytest內建的parametrize,來把引數傳遞給目標fixture函式,你希望把引數傳遞給哪個fixture函式就加哪個。比如這裡的
gen_token
和setup_before
,注意名稱與fixture名稱一致。 - indirect=True:作用是讓parametrize中的引數名稱,也就是
"gen_token"
當成函式執行,並且後面的引數值test_param
,作為"gen_token"
的傳參。 - request.param:接受傳參的fixture函式,使用
request.param
來獲取值。
fixture呼叫fixture
fixture之間的相互呼叫,在之前的文章裡已經有過詳述了。既然這裡setup_before
依賴gen_token
,之間傳遞呼叫即可setup_before(request, gen_token)
。
在各環節做了些print
列印出資訊,幫助理解執行過程。
test_case.py [100%]
============================== 1 passed in 0.08s ==============================
根目錄下gen_token()拿到的引數: (1, 4)
執行子級setup_before,拿到的傳參: (1, 4)
執行子級setup_before,拿到gen_token的返回值: api_token
.
測試用例裡拿到的gen_token返回值: api_token
執行測試用例test_case1...
測試用例test_case執行完畢,清理測試資料
Process finished with exit code 0
再看下gen_token
不返回token的情況,改下傳參test_param = [(2, 4)]
。
test_case.py [100%]
============================= 1 skipped in 0.08s ==============================s
根目錄下gen_token()拿到的引數: (2, 4)
執行子級setup_before,拿到的傳參: (2, 4)
執行子級setup_before,拿到gen_token的返回值: None
Skipped: 跳過
Process finished with exit code 0
測試用例不執行。