「原創宣告:保留所有權利,禁止轉載」
Pytest 順序執行,依賴執行,引數化執行
進行下面實驗前,需要安裝 python 和 pytest,我一般用 poetry 來管理,如何建立就是以下幾個命令:
poetry init
poetry add pytest --group test
-
Pytest 順序執行,依賴執行,引數化執行
- 0- 被測物件
- 1. 使用 pytest 進行測試這個服務的常見場景和解法
- 1.1 pytest-單獨測試一個方法
- 1.2 Pytest-測試方法 B 但是需要先執行測試方法 A
- 1.3 pytest - 引數化執行
- 2. 使用的一些小結 <!-- TOC -->
0- 被測物件
假設被測試物件就是一個計算加減乘除的一個服務,這裡把一個方法就等同於一個 API 介面,實際上也確實沒有
太大區別,一個是本地呼叫,一個是遠端呼叫,遠端呼叫需要一個客戶端,本地呼叫直接就用這個類呼叫了
"""
service functions for calculation
"""
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def divide(a, b):
return a * 1.0 / b
1. 使用 pytest 進行測試這個服務的常見場景和解法
- 單獨測試一個方法
- 測試方法 B 但是需要先執行測試方法 A
- 引數化測試,引數可能是靜態寫死的,也可能是動態的
1.1 pytest-單獨測試一個方法
使用如下方法就可以進行單獨的方法測試,基本原則就是: 一個方法一個測試,測試資料都固定
import allure
import pytest
from app.module_a.service import subtract, add
@allure.feature("減法結果為正")
def test_subtract_positive():
result = subtract(2, 1)
assert result == 1
@allure.feature("減法結果為為負數")
def test_subtract_negative():
result = subtract(1, 2)
assert result == -1
1.2 Pytest-測試方法 B 但是需要先執行測試方法 A
如果遇到: 測試方法 B 但是需要先執行測試方法 A,這裡面有一些小問題就是:
- 順序不能絕對保證: 如果透過執行 pytest 的命令列時候,有可能不能確保測試 A 一定跑在測試 B 前面
- 測試可讀性問題: s 不仔細看程式碼,不能看出來 - 測試方法 B 但是需要先執行測試方法 A
這個問題可以透過 pytest 的外掛 pytest-order 來解決:
poetry add pytest-order
測試程式碼如下: 透過@pytest.mark.order定於顯示的定於執行順序,好處有兩個:
- 確保順序
- 提高測試可讀性,一眼就看出來那個先跑那個後跑
- 不好的地方是: 單獨執行第二個測試: test_subtract_order 會報錯,但是因為寫了 order 標識, 大概一下子也能明白怎麼回事
context = {}
@pytest.mark.order(1)
def test_add_positive():
result = add(1, 2)
assert result == 3
context['USED_FOR_SUBTRACT'] = result
@allure.feature("被減數是加法函式計算出來的結果")
@pytest.mark.order(2)
def test_subtract_order():
result = subtract(1, context['USED_FOR_SUBTRACT'])
assert result == -2
如果使用 pytest-dependency 外掛解決,程式碼也類似,就不多說明了:
context = {}
@pytest.mark.order(1)
@user8cy()
def test_add_positive():
result = add(1, 2)
assert result == 3
context['USED_FOR_SUBTRACT'] = result
@user9cy(depends=["test_add_positive"])
def test_subtract_dep():
result = subtract(1, context['USED_FOR_SUBTRACT'])
assert result == -2
這裡面注意一點: 用來存資料的用字典會好那麼一點,為了避免一些想不到的麻煩我自己就一直用字典了,也沒有用 global 這樣的東西。
1.3 pytest - 引數化執行
- 有時很多 case 都很類似,只要給資料自動跑就行了,不想寫很多單獨的測試方法了,就用引數化執行, 最簡單的就是直接給上固定的資料, 以下程式碼一看就明白
fixed_params = [(1, 2, 3), (-1, 1, 0)]
@user10ize('a,b,expected', fixed_params)
def test_add_parameterized(a, b, expected):
actual = add(a, b)
assert actual == expected
- 有時呢,引數化的時候有一兩個數字是需要動態獲得以下的,那麼可以用以下方式簡單處理以下, 就是寫一個函式區構建這些引數化的測試資料
def dynamic_cases():
d_params = [(1, 2, 3), (-1, 1, 0)]
dynamic_case = (1, add(1, 2), 4)
d_params.append(dynamic_case)
return d_params
@user11ize('a,b,expected', dynamic_cases())
def test_add_parameterized(a, b, expected):
actual = add(a, b)
assert actual == expected
2. 使用的一些小結
有時可能更復雜,那麼其實呢,我自己的做法就是:
- 混合使用順序 order/依賴空 dependency 和引數化化進行處理
- 能引數化的和複雜的 case 分開,比如: A. 一些異常錯誤資料,出錯資訊的測試,這些引數化可能容易一些就引數化了 B. 複雜場景的,計算,拿前一個返回再構建後一個的人參之類的,乾脆就單獨寫一個測試方法了
- 不去想一個統一的解法,寫程式碼和在測試平臺上寫測試用例的最大的區別就是:測試平臺一般想用一種方法解決所有問題, 而自己寫程式碼的壞,就是完全自己控制靈活度, 各有好壞,既然自己寫程式碼了, 那就多多利用寫程式碼的靈活度解決自己的問題,有時找一個可以適用所有的方法可能很麻煩,不如直接手寫一個測試方法來的簡單直接 還節約一點時間。
如果覺得我的文章對您有用,請隨意打賞。您的支援將鼓勵我繼續創作!
打賞支援