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.小結
好了,今天的分享就到這里吧!!!謝謝各位的耐心閱讀。有問題加群交流討論!!!
您的肯定就是我進步的動力。如果你感覺還不錯,就請鼓勵一下吧!記得隨手點波 推薦 不要忘記哦!!!
別忘了點 推薦 留下您來過的痕跡