一、固件使用背景 在執行測試用例時,我們常常需要在測試用例執行的前後去完成一些額外的操作。例如針對於 Web 測試,在用例執行前需要打開瀏覽器,完成用戶登錄等一系列前置操作;在用例執行完成後,要清除瀏覽器緩存,關閉瀏覽器...... Pytest 框架提供的固件機制(又稱為夾具)可以幫我們實現一系列 ...
一、固件使用背景
在執行測試用例時,我們常常需要在測試用例執行的前後去完成一些額外的操作。例如針對於 Web 測試,在用例執行前需要打開瀏覽器,完成用戶登錄等一系列前置操作;在用例執行完成後,要清除瀏覽器緩存,關閉瀏覽器...... Pytest 框架提供的固件機制(又稱為夾具)可以幫我們實現一系列的前後置操作。
我們先創建一套測試用例:
二、前後置函數
1. 測試方法級別
setup
和 teardown
方法作用於每一個測試方法,每個測試方法執行之前都會先去執行 setup
方法,執行之後都會再去執行 teardown
方法。
1 # cases/test_cases.py 2 class TestCase: 3 4 def setup(self): 5 print("\n測試方法執行前做對應的操作!!!") 6 7 def teardown(self): 8 print("\n測試方法執行後做對應的操作!!!") 9 10 def test_case_001(self): 11 print("模擬測試案例001") 12 13 def test_case_002(self): 14 print("模擬測試案例002") 15 16 def test_case_003(self): 17 print("模擬測試案例003")
需要註意的是:
-
如果前後置方法是定義在測試類內部的,那麼作用的對象是當前測試類中的每一個測試方法,其他測試類和外部的測試方法將不會被影響。
1 # cases/test_cases.py 2 class TestCase: 3 4 def setup(self): 5 print("\n測試方法執行前做對應的操作!!!") 6 7 def teardown(self): 8 print("\n測試方法執行後做對應的操作!!!") 9 10 def test_case_001(self): 11 print("模擬測試案例001") 12 13 def test_case_002(self): 14 print("模擬測試案例002") 15 16 def test_case_003(self): 17 print("模擬測試案例003") 18 19 20 class TestCase2: 21 def test_case_004(self): 22 print("模擬測試案例004") 23 24 def test_case_005(self): 25 print("模擬測試案例005") 26 27 28 def test_outer_case(): 29 print("模擬測試外部的測試方法")
-
如果前後置方法是定義在測試類外部的,那麼作用的對象是定義在外部的測試方法,測試類中的測試方法不會被影響。
1 # cases/test_cases.py 2 def setup(): 3 print("\n測試方法執行前做對應的操作!!!") 4 5 6 def teardown(): 7 print("\n測試方法執行後做對應的操作!!!") 8 9 class TestCase: 10 11 def test_case_001(self): 12 print("模擬測試案例001") 13 14 def test_case_002(self): 15 print("模擬測試案例002") 16 17 def test_case_003(self): 18 print("模擬測試案例003") 19 20 21 class TestCase2: 22 def test_case_004(self): 23 print("模擬測試案例004") 24 25 def test_case_005(self): 26 print("模擬測試案例005") 27 28 29 def test_outer_case(): 30 print("模擬測試外部的測試方法")
2. 測試類級別
setup_class
和 teardown_class
方法作用於當前的測試類,每個測試類執行之前都會先去執行 setup_class
方法,執行之後都會再去執行 teardown_class
方法。測試方法並不會受到這兩個方法的影響。
1 # cases/test_cases.py 2 class TestCase: 3 4 def test_case_001(self): 5 print("模擬測試案例001") 6 7 def test_case_002(self): 8 print("模擬測試案例002") 9 10 def test_case_003(self): 11 print("模擬測試案例003") 12 13 14 class TestCase2: 15 def setup_class(self): 16 print("\n測試方法執行前做對應的操作!!!") 17 18 def teardown_class(self): 19 print("\n測試方法執行後做對應的操作!!!") 20 21 def test_case_004(self): 22 print("模擬測試案例004") 23 24 def test_case_005(self): 25 print("模擬測試案例005")
三、裝飾器實現
使用前後置函數的方式作用的對象都是一個模塊內或者是一個測試類中的全體對象,沒有辦法做到只作用於部分對象。Pytest
提供了 @pytest.fixture()
方法來實現部分用例的前後置操作。
1. 簡單使用
-
第一步,先自定義一個生成器方法
1 def my_fixture(): 2 print("前置操作") 3 yield 4 print("後置操作")
-
第二步,添加裝飾器方法
1 import pytest 2 3 @pytest.fixture() 4 def my_fixture(): 5 print("前置操作") 6 yield 7 print("後置操作")
-
第三步,將函數名作為參數,傳遞給需要做前後置操作的測試方法。測試方法在執行前會先去執行生成器函數中
yield
的前半部分代碼;測試方法執行完成後,會去執行生成器函數中yield
的後半部分代碼。
1 # cases/test_cases.py 2 import pytest 3 4 @pytest.fixture() 5 def my_fixture(): 6 print("前置操作") 7 yield 8 print("後置操作") 9 10 class TestCase: 11 12 def test_case_001(self, my_fixture): 13 print("模擬測試案例001") 14 15 def test_case_002(self): 16 print("模擬測試案例002") 17 18 def test_case_003(self): 19 print("模擬測試案例003")
2. 相關參數詳解
2.1 autouse
值為 True
時,表示固件自動執行,即不需要在對應的測試方法中引用也會觸發,預設值為 False
1 # cases/test_cases.py 2 import pytest 3 4 @pytest.fixture(autouse=True) 5 def my_fixture(): 6 print("\n前置操作") 7 yield 8 print("\n後置操作") 9 10 11 class TestCase: 12 # 並未傳入固件使用 13 def test_case_001(self): 14 print("模擬測試案例001") 15 16 def test_case_002(self): 17 print("模擬測試案例002") 18 19 def test_case_003(self): 20 print("模擬測試案例003")
2.2 scope
表示的是被 @pytest.fixture
標記的方法的作用域,有以下幾個值:
-
function:作用於測試方法級別,每個函數或方法都會調用
1 # cases/test_cases.py 2 import pytest 3 4 @pytest.fixture(scope="function", autouse=True) 5 def my_fixture(): 6 print("\n前置操作") 7 yield 8 print("\n後置操作") 9 10 11 class TestCase: 12 13 def test_case_001(self): 14 print("模擬測試案例001") 15 16 def test_case_002(self): 17 print("模擬測試案例002") 18 19 def test_case_003(self): 20 print("模擬測試案例003")
-
class:作用於測試類級別,測試類執行時會執行一次固件
1 # cases/test_cases.py 2 import pytest 3 4 @pytest.fixture(scope="class", autouse=True) 5 def my_fixture(): 6 print("\n前置操作") 7 yield 8 print("\n後置操作") 9 10 class TestCase: 11 12 def test_case_001(self): 13 print("模擬測試案例001") 14 15 def test_case_002(self): 16 print("模擬測試案例002") 17 18 def test_case_003(self): 19 print("模擬測試案例003") 20 21 class TestCase2: 22 23 def test_case_004(self): 24 print("模擬測試案例004") 25 26 def test_case_005(self): 27 print("模擬測試案例005")
-
module:作用於測試模塊,測試模塊(即
py
文件)執行時會執行一次固件
-
session:作用於會話,可以跨多個
.py
文件,若多個模塊中的用例都調用了 fixture,只會運行一次
1 ####################### cases/test_cases.py ######################## 2 import pytest 3 4 @pytest.fixture(scope="session", autouse=True) 5 def my_fixture(): 6 print("\n前置操作") 7 yield 8 print("\n後置操作") 9 10 class TestCase: 11 12 def test_case_001(self): 13 print("模擬測試案例001") 14 15 def test_case_002(self): 16 print("模擬測試案例002") 17 18 def test_case_003(self): 19 print("模擬測試案例003") 20 21 ####################### cases/test_cases_2.py ############################## 22 class TestCase2: 23 24 def test_case_004(self): 25 print("模擬測試案例004") 26 27 def test_case_005(self): 28 print("模擬測試案例005")
2.3 params
使用裝飾器方的固件,還可以進行參數傳遞。參數的類型支持以下四種:
-
列表
-
元組
-
字典列表:[{},{},{}]
-
字典元組:({},{},{})
我們先列印一下測試方法中接收的固件名的值是啥
1 import pytest 2 3 @pytest.fixture(scope="function") 4 def my_fixture(): 5 print("一些操作......") 6 7 class TestCase: 8 9 def test_case_001(self, my_fixture): 10 print(f"模擬測試案例001----{my_fixture}") 11 12 def test_case_002(self): 13 print("模擬測試案例002") 14 15 def test_case_003(self): 16 print("模擬測試案例003")
在固件中我們嘗試返回一個值試試:
1 import pytest 2 3 @pytest.fixture(scope="function") 4 def my_fixture(): 5 print("一些操作......") 6 return "success" 7 8 class TestCase: 9 10 def test_case_001(self, my_fixture): 11 print(f"模擬測試案例001----{my_fixture}") 12 13 def test_case_002(self): 14 print("模擬測試案例002") 15 16 def test_case_003(self): 17 print("模擬測試案例003")
可見在測試方法中傳入固件名,除了可以執行固件對應的操作,還可以拿到固件的返回值。那麼想結合 params
參數在固件中傳值就十分容易了:
1 import pytest 2 3 @pytest.fixture(scope="function", params=["aaa", "bbb", "ccc"]) 4 def my_fixture(request): # 固定寫法,使用參數時必須接收一個request變數 5 print("一些操作......") 6 return request.param # 固定寫法,返回參數 7 8 class TestCase: 9 10 def test_case_001(self, my_fixture): 11 print(f"模擬測試案例001----{my_fixture}") 12 13 def test_case_002(self): 14 print("模擬測試案例002") 15 16 def test_case_003(self): 17 print("模擬測試案例003")
被標記的測試方法被執行了三次,是因為傳的參數有三個值,每執行一次就會傳一個值過去。
如果固件要執行前後置操作,就不能用 return
返回值了,要使用 yield
:
1 import pytest 2 3 @pytest.fixture(scope="function", params=["aaa", "bbb", "ccc"]) 4 def my_fixture(request): # 固定寫法,使用參數時必須接收一個request變數 5 print("前置操作......") 6 yield request.param # 固定寫法,返回參數 7 print("後置操作......") 8 9 class TestCase: 10 11 def test_case_001(self, my_fixture): 12 print(f"模擬測試案例001----{my_fixture}") 13 14 def test_case_002(self): 15 print("模擬測試案例002") 16 17 def test_case_003(self): 18 print("模擬測試案例003")