电竞比分网-中国电竞赛事及体育赛事平台

分享

【pytest官方文檔】解讀fixtures - 7. Teardown處理,yield和addfinalizer

 行者花雕 2022-08-04 發(fā)布于北京

當(dāng)我們運(yùn)行測(cè)試函數(shù)時(shí),我們希望確保測(cè)試函數(shù)在運(yùn)行結(jié)束后,可以自己清理掉對(duì)環(huán)境的影響。
這樣的話,它們就不會(huì)干擾任何其他的測(cè)試函數(shù),更不會(huì)日積月累的留下越來越多的測(cè)試數(shù)據(jù)。

用過unittest的朋友相信都知道teardown這個(gè)函數(shù),做的是一樣的事情,那么下面姑且就把這種“善后”工作的代碼
叫做teardown代碼吧。

而pytest中的fixture,也提供了這樣一個(gè)非常有用的系統(tǒng),我們可以在里面定義teardown代碼。

這里可以使用2種方式來實(shí)現(xiàn),分別是yieldaddfinalizer

一、yield fixtures(推薦)

1, yield 和 return

在有yield的fixtures函數(shù)中,關(guān)鍵字yield 可以代替 return,可以把fixture里的一些對(duì)象傳遞給調(diào)用它們的fixture函數(shù)或者測(cè)試函數(shù)。
就像其他普通的fixture函數(shù)一樣。區(qū)別僅僅是:

  1. yield替換掉了return
  2. teardown代碼放置在yield之后

2, yield的執(zhí)行順序

pytest在執(zhí)行fixture函數(shù)時(shí),會(huì)根據(jù)fixture函數(shù)之間的線性關(guān)系順序調(diào)用的。
但是,當(dāng)測(cè)試函數(shù)運(yùn)行結(jié)束的時(shí)候,pytest又會(huì)按照之前的順序反方向來執(zhí)行fixture中yield之后的代碼。
結(jié)合示例看下,這里沒有引用官方示例了,手寫一個(gè)直觀些的:

import pytest


@pytest.fixture
def fixture_one():
    print("\n執(zhí)行fixture_one")
    return 1


@pytest.fixture
def fixture_two(fixture_one):
    print("\n執(zhí)行fixture_two")
    yield 2
    print("\n執(zhí)行fixture_two的teardown代碼")


@pytest.fixture
def fixture_adding(fixture_one, fixture_two):
    print("\n執(zhí)行fixture_adding")
    result = fixture_one + fixture_two
    yield result
    print("\n執(zhí)行fixture_adding的teardown代碼")


def test_demo(fixture_two, fixture_adding):
    print("\n執(zhí)行測(cè)試函數(shù)test_demo")
    assert fixture_adding == 3

代碼中,fixture中調(diào)用多個(gè)fixture,測(cè)試函數(shù)中調(diào)用多個(gè)fixture,通過前面幾章的接觸,
相信大家這時(shí)候已經(jīng)可以梳理出前后調(diào)用順序了:

  1. test_demo 測(cè)試函數(shù),先去調(diào)用fixture函數(shù) fixture_two,然后調(diào)用 fixture_adding。
  2. 在fixture函數(shù) fixture_two中,又會(huì)去調(diào)用另一個(gè)fixture函數(shù) fixture_one。
  3. 在fixture函數(shù) fixture_adding中,調(diào)用了 fixture_one、fixture_two。

所以,fixture函數(shù)的先后順序是:fixture_onefixture_two、fixture_adding
那么,可以得知測(cè)試結(jié)束后的teardown代碼執(zhí)行順序:fixture_adding、fixture_two。

運(yùn)行一下代碼,驗(yàn)證下結(jié)果是否符合我們的梳理:

============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: D:\練習(xí)\demo_fixture
plugins: allure-pytest-2.8.32, celery-4.3.0, Faker-4.14.2, base-url-1.4.2, html-2.1.1, metadata-1.10.0collected 1 item

test_module.py 
執(zhí)行fixture_one

執(zhí)行fixture_two

執(zhí)行fixture_adding
.
執(zhí)行測(cè)試函數(shù)test_demo

執(zhí)行fixture_adding的teardown代碼

執(zhí)行fixture_two的teardown代碼
                                                         [100%]

============================== 1 passed in 0.09s ==============================

結(jié)果與我們剛才梳理的一致。

但是,值得注意的是,就算是teardown的代碼是按照正確的順序執(zhí)行,也不能保證代碼能正常執(zhí)行的。
比如說teardown里的某些代碼執(zhí)行異常了,導(dǎo)致別的清理動(dòng)作也沒法執(zhí)行。
這里就涉及到另一個(gè)點(diǎn)了:健壯的fixture結(jié)構(gòu)應(yīng)該是什么樣子。這個(gè)官方文檔另起進(jìn)行說明,這里同樣。

二、addfinalizer

1.request.addfinalizer把函數(shù)變成終結(jié)器

在pytest中想要做teardown的處理,除了使用帶有yield的fixture函數(shù),還可以直接添加終結(jié)器。
直接來看示例代碼:

import pytest


@pytest.fixture()
def demo_fixture(request):
    print("\n這個(gè)fixture在每個(gè)case前執(zhí)行一次")
    def demo_finalizer():
        print("\n在每個(gè)case完成后執(zhí)行的teardown")

    #注冊(cè)demo_finalizer為終結(jié)函數(shù)    
    request.addfinalizer(demo_finalizer)

def test_01(demo_fixture):
    print("\n===執(zhí)行了case: test_01===")

def test_02(demo_fixture):
    print("\n===執(zhí)行了case: test_02===")

看下運(yùn)行結(jié)果:

============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: D:\練習(xí)\demo_fixture
plugins: allure-pytest-2.8.32, celery-4.3.0, Faker-4.14.2, base-url-1.4.2, html-2.1.1, metadata-1.10.0collected 2 items

test_module.py 
這個(gè)fixture在每個(gè)case前執(zhí)行一次
.
===執(zhí)行了case: test_01===

在每個(gè)case完成后執(zhí)行的teardown

這個(gè)fixture在每個(gè)case前執(zhí)行一次
.
===執(zhí)行了case: test_02===

在每個(gè)case完成后執(zhí)行的teardown
                                                        [100%]

============================== 2 passed in 0.10s ==============================
Process finished with exit code 0

運(yùn)行結(jié)果可以看出,效果與yield是一致的。這算是一個(gè)固定寫法,關(guān)于request文檔中也有另外的講解,屆時(shí)再分享。

2.request.addfinalizer注冊(cè)多個(gè)終結(jié)器函數(shù)

上方代碼是一個(gè)終結(jié)函數(shù),如果要注冊(cè)多個(gè)呢?

import pytest


@pytest.fixture()
def demo_fixture(request):
    print("\n這個(gè)fixture在每個(gè)case前執(zhí)行一次")
    def demo_finalizer():
        print("\n在每個(gè)case完成后執(zhí)行的teardown")
    def demo_finalizer2():
        print("\n在每個(gè)case完成后執(zhí)行的teardown2")

    #注冊(cè)demo_finalizer為終結(jié)函數(shù)
    request.addfinalizer(demo_finalizer)
    request.addfinalizer(demo_finalizer2)

def test_01(demo_fixture):
    print("\n===執(zhí)行了case: test_01===")

def test_02(demo_fixture):
    print("\n===執(zhí)行了case: test_02===")

if __name__ == '__main__':
    pytest.main(['-s', 'test_module.py'])

運(yùn)行結(jié)果:

============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: D:\練習(xí)\demo_fixture
plugins: allure-pytest-2.8.32, celery-4.3.0, Faker-4.14.2, base-url-1.4.2, html-2.1.1, metadata-1.10.0collected 2 items

test_module.py 
這個(gè)fixture在每個(gè)case前執(zhí)行一次
.
===執(zhí)行了case: test_01===

在每個(gè)case完成后執(zhí)行的teardown2

在每個(gè)case完成后執(zhí)行的teardown

這個(gè)fixture在每個(gè)case前執(zhí)行一次
.
===執(zhí)行了case: test_02===

在每個(gè)case完成后執(zhí)行的teardown2

在每個(gè)case完成后執(zhí)行的teardown
                                                        [100%]

============================== 2 passed in 0.09s ==============================
Process finished with exit code 0

這里要注意的是,多個(gè)終結(jié)器的情況下,執(zhí)行的順序是與注冊(cè)時(shí)候相反的

3.yield和addfinalizer的區(qū)別

目前從官方文檔中看到的是

We have to be careful though, because pytest will run that finalizer once it’s been added, 
even if that fixture raises an exception after adding the finalizer. 

一旦添加了終結(jié)器,pytest便會(huì)執(zhí)行。

但是,當(dāng)我嘗試在setup代碼中進(jìn)行拋錯(cuò),終結(jié)器的代碼卻并沒有執(zhí)行。
嘗試搜索外網(wǎng)暫時(shí)也沒得到有效的幫助,只能在GitHub上向pytest提了issue了,這里算是埋下一個(gè)坑,待后續(xù)解決。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多