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共用的信息,當然通過類的繼承也可以達到共用的作用。

以我這裡的做法是

  1. 透過command pytest_addoption 去設定command

  2. @pytest.fixture 定義所需要的fixture

  3. 透過 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()

results matching ""

    No results matching ""