fixture 介紹
基本上我覺得這幾篇寫的不錯 http://cuyu.github.io/python/2016/09/19/Play-Python-Library%E4%B9%8Bpytest-fixture%E7%AF%87
http://senarukana.github.io/2015/05/29/pytest-fixture/
引用其中一段
pytest中,一個fixture其實就是一個函數,函數名就是fixture的名稱。關於fixture,pytest在run一個test方法的時候,大概流程如下:
收集該test方法的作用域內的所有fixture; 這個作用域包括該test case所屬的class,module等不同作用域的疊加(遇到同名的fixture,更里層的會覆蓋更外層的):
The discovery of fixtures functions starts at test classes, then test modules, then conftest.py files and finally builtin and third party plugins.
收集該test方法的pytest參數(通過pytest.mark.parametrize來定義);
對該test方法的輸入根據該作用域內的fixture名稱或pytest參數(遇到pytest參數和fixture同名的,pytest參數會覆蓋fixture)進行填充後執行。
pytest中的fixture提供了一個很好的對象管理方式,我們可以將測試代碼中經常用到的一些對象定義為fixture來統一進行管理,而省去了很多重復的代碼(這點就像with-statement,不但減少了代碼量,而且避免了代碼中類似資源未正確釋放的情況)。
fixture是pytest特有的功能
它用pytest.fixture標識,定義在函數前面。在你編寫測試函數的時候,你可以將此函數名稱做為傳入參數,pytest將會以依賴註入方式,將該函數的返回值作為測試函數的傳入參數。
從我的理解而言,fixture會適用於以下幾類對象:
- 資源類的對象。比如網路資源,fixture中可以進行網路的連接、斷開等操作。
- 全局變量。比如一些test共用的信息,當然通過類的繼承也可以達到共用的作用。
以我這裡的做法是
透過command pytest_addoption 去設定command
@pytest.fixture 定義所需要的fixture
透過 pytest_generate_tests決定要生成什麼測試資料或是決定要skip method
fixture function(預設是function)
用法: 他在每一個function重新建立一次
如下: 我們定義了一個hello function 將他當成參數傳入到function內去做
@pytest.fixture()
def hello():
return "hello"
def test_string(hello):
assert hello == "hello", "fixture should return hello"
conftest 相同的fixture裡面會覆蓋前面宣告的
舉個例子
conftest.py
|--casino/
|--conftest.py
|--test_fixture.py
假設外層的conftest.py 我們定義如下:
import pytest
@pytest.fixture
def customhello():
return "outside hello"
內層的conftest.py 我們定義如下:
import pytest
@pytest.fixture
def customhello():
return "inside hello"
def test_fixtureCompare(customhello):
print(customhello)
出來的結果會這樣
相同的fixture名稱裡面會覆蓋前面宣告的
fixture module
用法: scope=”module”表示一個模塊fixture只初始化一次,如果一個模塊使用多次該fixture,將會使用同個對像
@pytest.fixture(scope="module")
def customhellomodule():
print("outside hello")
return 1
檔案架構如下
conftest.py
|--fixtureModule/
|--test_fixture_module.py
|--test_fixture_module1.py
程式碼都一樣是長這樣
def test_1_that_needs_resource_a(customhellomodule):
print('test_1_that_needs_resource_a()')
print(customhellomodule)
def test_2_that_does_not(customhellomodule):
print('\ntest_2_that_does_not()')
print(customhellomodule)
def test_3_that_does(customhellomodule):
print('\ntest_3_that_does()')
print(customhellomodule)
可以發現他將每一個test . py 當成一個module, 只會初始化一次
其他狀態下都會直接return 值
fixture session
用法: scope=”session”,表示全局初始化一次。通常用於全局系統初始化.
@pytest.fixture(scope="session")
def customhellomodule():
print("outside hello")
return 1
Fixture’s tear down
其中,在fixture定義中yield之後的語句是會在fixture對像超出定義的scope時執行的。
用途就是假設透過建立smtp or selenium webdriver, 最後需要做關閉的動作 他會在所有執行完成後
去呼叫yield之後的code, yield 就有點像是return 會回傳生成的東西
import smtplib
import pytest
@pytest.fixture(scope="module")
def smtp(request):
smtp = smtplib.SMTP("smtp.gmail.com")
yield smtp # provide the fixture value
print("teardown smtp")
smtp.close()
此處會生效是因為pytest-selenium 共用的driver ,等於共用driver這個變數
@pytest.yield_fixture
def mobileSelenium(request):
mobile_emulation = {
"deviceMetrics": { "width": 360, "height": 640, "pixelRatio": 3.0 },
"userAgent": "Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19" }
chrome_options = Options()
chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
driver = webdriver.Chrome(chrome_options = chrome_options)
request.node._driver = driver
yield driver
driver.quit()