【pytest官方文檔】解讀fixtures - 8. yield和addfinalizer的區別(填坑)


上一章中,文末留下了一個坑待填補,疑問是這樣的:

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

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. 

一旦添加了終結器,pytest便會執行。

但是,當我嘗試在setup代碼中進行拋錯,終結器的代碼卻並沒有執行。
嘗試搜索外網暫時也沒得到有效的幫助,只能在GitHub上向pytest提了issue了,這里算是埋下一個坑,待后續解決。

一、問題回顧

其實說到底還是我理解的不對,可能當時自己處在疑問中難免就會陷入進死循環,后來在github上經過別人提點方才醒悟。
先來看下當時我嘗試演示出上述結果的代碼,也就是:setup代碼中進行拋錯,終結器的代碼卻並沒有執行。

代碼分為2部分,一個是fixture函數代碼,另一個則是測試用例。代碼是不能直接copy出來運行的,是我在項目的用例中
進行改造的,在這里僅僅幫助說明意思。

# content of conftest.py

@pytest.fixture()
def init_data_allot_task(request):
    query_sql = """
    SELECT id FROM `sm_purchase_allot` WHERE `status`!=5
    """
    db = DB()
    data = db.fetch_one(query_sql)
    db.close()

    def demo_finalizer():
        print("running finalizer code...")
    request.addfinalizer(demo_finalizer)
    return data
# content of testcase
...
def test_allot_detail(init_data_allot_task):
    """

    """
    payload = {
          "allotId": init_data_allot_task[0]
        }
    r = requests.post(QA_URL + API_URL, json=payload, headers=HEADER)
    result = r.json()

    assert result["result"] == "ok"
    assert result["errmsg"] == "success"
    assert len(result["row"]["taskListOfPage"]["resultData"]) > 0

最開始我想做的是,在fixture函數中,讓代碼db = DB()拋出一個mysql連接超時的錯誤,
然后就能在控制台中看到"running finalizer code..."的輸出。

但是我執行后,並沒有看到預期的輸出,說明setup代碼拋錯后,addfinalizer代碼並沒有執行。

最后經過github上朋友指點后,發現還是我自己理解錯了。

二、問題解決

還是來看下官方的原文:

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. 

這句話意思其實是說,當finalizer 一旦添加成功后,pytest就會去執行它。就算是fixture函數在添加了finalizer之后
拋出了異常。

按照這樣理解的話,那我在fixture函數中的代碼就有問題了。因為db = DB()代碼在request.addfinalizer(demo_finalizer)
之前就拋錯了,那么實際上並沒有執行到添加終結器的這行代碼,所以終結器都還沒添加成功,又怎么會去執行呢?

終於我明白過來了,於是調整了代碼順序,把request.addfinalizer(demo_finalizer)放到前面去,然后再接上fixture的代碼:

# content of conftest.py
@pytest.fixture()
def init_data_allot_task(request):
    query_sql = """
    SELECT id FROM `sm_purchase_allot` WHERE `status`!=5 
    """
    def demo_finalizer():
        print("running finalizer code...")
    request.addfinalizer(demo_finalizer)
    print("running setup code...")

    db = DB()
    data = db.fetch_one(query_sql)
    db.close()
    return data

如此來看,我們會先看到"running setup code..."的輸出,然后看到mysql拋錯,
最后仍然可以看到"running setup code..."的輸出。

運行代碼驗證一下:

這下就對了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM