《帶你裝B,帶你飛》pytest修仙之路5 - yield操作


1. 簡介

  上一篇中,我們剛剛實現了在每個用例之前執行初始化操作,那么用例執行完之后如需要清除數據(或還原)操作,可以使用 yield 來實現。fixture通過scope參數控制setup級別,既然有setup作為用例之前前的操作,用例執行完之后那肯定也有teardown操作。
這里用到fixture的teardown操作並不是獨立的函數,用yield關鍵字呼喚teardown操作。fixture的teardown操作並不是獨立的函數,可以用yield關鍵字呼喚teardown操作。 

  我們之前學習的都是測試用例的前置固件,也就是相當於“setup”。說到這,細心的你可能想到了,那有沒有什么方式可以表示出“teardown”?這就是我們今天學習的yield和addfinalizer。

yield

  yield是一個關鍵字,它不是單獨存在的,要寫在fixtrue標記的固件中。

  我們在聲明的固件myfixture中加入yield關鍵字,在它下面寫測試用例執行后想要運行的代碼;其他有關於固件的使用沒有任何差別。需要說明的一點是我們在pytest主函數中增加了一個參數“–setup-show”,他會顯示出固件的執行情況。

  fixture里面的teardown用yield來喚醒teardown的執行

  如果測試用例中的代碼出現異常或者斷言失敗,並不會影響他的固件中yield后的代碼執行;但是如果固件中的yield之前的代碼也就是相當於setup部分的帶代碼,出現錯誤或斷言失敗,那么yield后的代碼將不會再執行,當然測試用例中的代碼也不會執行。

  我們也可以通過request.addfinalizer()的方式實現“teardown”

  我們在固件中傳入request參數;又在固件中定義了一個內置函數;最后將定義的內置函數添加到request的addfinalizer中

2. scope="function"

當 pytest.fixture(scope="function") 時,pytest的yieId 類似unittest的teartown。每個方法(函數)都會執行一次

1.新建 test_bjhg_function1.py文件,我們看一下是不是這樣的。

2.1 代碼實現:

2.2 參考代碼:

# coding=utf-8
# 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行

# 2.注釋:包括記錄創建時間,創建人,項目名稱。
'''
Created on 2020-04-20
@author: 北京-宏哥
Project:《帶你裝B,帶你飛》pytest修仙之路5 - yield操作
'''
# 3.導入模塊
import pytest

@pytest.fixture(scope="function")
def login():
    print("登錄成功")
    yield
    print("用例執行完成,收尾")

def test1(login):
    print('操作1')
    print("-----------------------------------------------")

def test2(login):
    print('操作2')
    print("-----------------------------------------------")

def test3(login):
    print('操作3')
    print("-----------------------------------------------")

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

2.3 運行結果:

運行代碼后,控制台打印如下圖的結果

從結果看出,雖然test1,test2,test3三個地方都調用了login函數,並且它會在每一個用例前執行一次

2.如果test1不調用,test2(調用login),test3不調用,運行順序會是怎樣的?

2.4 參考代碼:

# coding=utf-8
# 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行

# 2.注釋:包括記錄創建時間,創建人,項目名稱。
'''
Created on 2020-04-20
@author: 北京-宏哥
Project:《帶你裝B,帶你飛》pytest修仙之路5 - yield操作
'''
# 3.導入模塊
import pytest

@pytest.fixture(scope="function")
def login():
    print("登錄成功")
    yield
    print("用例執行完成,收尾")

def test1():
    print('操作1')
    print("-----------------------------------------------")

def test2(login):
    print('操作2')
    print("-----------------------------------------------")

def test3():
    print('操作3')
    print("-----------------------------------------------")

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

2.5 運行結果:

運行代碼后,控制台打印如下圖的結果

從結果看出,function級別的fixture在當前.py模塊里,只會在用例(test_s2)第一次調用前執行一次

3.scope="module"

1.fixture參數scope=”module”,module作用是整個.py文件都會生效( 整個文件只會執行一次),用例調用時,參數寫上函數名稱就行

3.1 代碼實現:

3.2 參考代碼:

# coding=utf-8
# 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行

# 2.注釋:包括記錄創建時間,創建人,項目名稱。
'''
Created on 2020-04-20
@author: 北京-宏哥
Project:《帶你裝B,帶你飛》pytest修仙之路5 - yield操作
'''
# 3.導入模塊
import pytest

@pytest.fixture(scope="module")
def login():
    print("登錄成功")
    yield
    print("用例執行完成,收尾")

def test1(login):
    print('操作1')
    print("-----------------------------------------------")

def test2(login):
    print('操作2')
    print("-----------------------------------------------")

def test3(login):
    print('操作3')
    print("-----------------------------------------------")

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

3.3 運行結果:

運行代碼后,控制台打印如下圖的結果

從結果看出,雖然test1,test2,test3三個地方都調用了login函數,但是它只會在第一個用例前執行一次

2.如果test1不調用,test2(調用login),test3不調用,運行順序會是怎樣的?

3.4 參考代碼:

# coding=utf-8
# 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行

# 2.注釋:包括記錄創建時間,創建人,項目名稱。
'''
Created on 2020-04-20
@author: 北京-宏哥
Project:《帶你裝B,帶你飛》pytest修仙之路5 - yield操作
'''
# 3.導入模塊
import pytest

@pytest.fixture(scope="module")
def login():
    print("登錄成功")
    yield
    print("用例執行完成,收尾")

def test1():
    print('操作1')
    print("-----------------------------------------------")

def test2(login):
    print('操作2')
    print("-----------------------------------------------")

def test3():
    print('操作3')
    print("-----------------------------------------------")

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

3.5 運行結果:

運行代碼后,控制台打印如下圖的結果

從結果看出,module級別的fixture在當前.py模塊里,只會在用例(test_s2)第一次調用前執行一次

4. yield執行teardown

  細心的童鞋或者小伙伴可以看到,我前邊的代碼中有一個yield關鍵字,大家有點好奇是做什么的,這一小節就給你答疑解惑。其實就是用來喚醒teardown。

1.fixture里面的teardown用yield來喚醒teardown的執行

4.1 代碼實現:

4.2 參考代碼:

# coding=utf-8
# 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行

# 2.注釋:包括記錄創建時間,創建人,項目名稱。
'''
Created on 2020-04-20
@author: 北京-宏哥
Project:《帶你裝B,帶你飛》pytest修仙之路5 - yield操作
'''
# 3.導入模塊
import pytest

@pytest.fixture(scope="module")
def login():
    print("登錄成功")
    yield
    print("執行teardown!")
    print("用例執行完成,收尾")

def test1(login):
    print('操作1')
    print("-----------------------------------------------")

def test2(login):
    print('操作2')
    print("-----------------------------------------------")

def test3(login):
    print('操作3')
    print("-----------------------------------------------")

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

4.3 運行結果:

運行代碼后,控制台打印如下圖的結果

5. yield遇到異常

1.如果其中一個用例出現異常,不影響yield后面的teardown執行,運行結果互不影響,並且在用例全部執行完之后,會呼喚teardown的內容

5.1 代碼實現:

5.2 參考代碼:

# coding=utf-8
# 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行

# 2.注釋:包括記錄創建時間,創建人,項目名稱。
'''
Created on 2020-04-20
@author: 北京-宏哥
Project:《帶你裝B,帶你飛》pytest修仙之路5 - yield操作
'''
# 3.導入模塊
import pytest

@pytest.fixture(scope="module")
def login():
    print("登錄成功")
    yield
    print("執行teardown!")
    print("用例執行完成,收尾")

def test1(login):
    print('操作1')
    print("-----------------------------------------------")
    # 如果第一個用例異常了,不影響其他的用例執行
    raise NameError  # 模擬異常

def test2(login):
    print('操作2')
    print("-----------------------------------------------")

def test3(login):
    print('操作3')
    print("-----------------------------------------------")

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

5.3 運行結果:

運行代碼后,控制台打印如下圖的結果

2.如果在setup就異常了,那么是不會去執行yield后面的teardown內容了

3.yield也可以配合with語句使用,以下是官方文檔給的案例

# 官方文檔案例
# content of test_yield2.py

import smtplib
import pytest

@pytest.fixture(scope="module")
def smtp():
    with smtplib.SMTP("smtp.gmail.com") as smtp:
        yield smtp  # provide the fixture value

6.addfinalizer終結函數

1.除了yield可以實現teardown,在request-context對象中注冊addfinalizer方法也可以實現終結函數。

# 官方案例

# content of conftest.py
import smtplib
import pytest

@pytest.fixture(scope="module")
def smtp_connection(request):
    smtp_connection = smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
    def fin():
        print("teardown smtp_connection")
        smtp_connection.close()
    request.addfinalizer(fin)
    return smtp_connection  # provide the fixture value

2.yield和addfinalizer方法都是在測試完成后呼叫相應的代碼。但是addfinalizer不同的是:

  • 他可以注冊多個終結函數。

  • 這些終結方法總是會被執行,無論在之前的setup code有沒有拋出錯誤。這個方法對於正確關閉所有的fixture創建的資源非常便利,即使其一在創建或獲取時失敗

7.小結

 好了,今天的分享就到這里吧!!!謝謝各位的耐心閱讀。有問題加群交流討論!!!

 

您的肯定就是我進步的動力。如果你感覺還不錯,就請鼓勵一下吧!記得隨手點波  推薦  不要忘記哦!!!

別忘了點 推薦 留下您來過的痕跡

 

參考文檔:https://docs.pytest.org/en/latest/


免責聲明!

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



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