練習
在本練習中,您將使用 pytest 搭配 parametrize 來測試函式。 然後,您會更新測試類別來使用固件,而非 setup() 和 teardown() 方法。 使用 parametrize 和使用固件可讓您在建立或更新測試時變得更有彈性。
步驟 1 - 在此練習中新增一個測試檔案
新建一個名為 test_advanced.py 的測試檔案並新增以下程式碼:
def str_to_bool(string): if string.lower() in ['yes', 'y', '1']: return True elif string.lower() in ['no', 'n', '0']: return False函式
str_to_bool()會接受字串做為輸入,並根據其內容傳回True或False值。請在相同檔案中附加
str_to_bool()函式的測試。 使用pytest.mark.parametrize()先測試所有 true 值:import pytest @pytest.mark.parametrize("string", ['Y', 'y', '1', 'YES']) def test_str_to_bool_true(string): assert str_to_bool(string) is True接下來,使用 false 值附加另一個測試:
@pytest.mark.parametrize("string", ['N', 'n', '0', 'NO']) def test_str_to_bool_false(string): assert str_to_bool(string) is False現在有兩項測試涵蓋
True和False傳回值的所有可能輸入。
注意
在與實際程式碼相同的檔案中執行測試並不常見。 為了操作簡單,本練習中的範例會在相同檔案內執行實際程式碼。 在實際的 Python 專案中,您會發現測試是以測試中程式碼的檔案和目錄作區隔。
步驟 2 - 執行測試和探索報告
在您新增測試之後,下一個步驟是執行 pytest 並檢查輸出。 使用增加的詳細程度旗標 (-v),您可以看到所有輸入值都會被視為個別的測試。
$ pytest -v test_avanced.py
============================= test session starts ==============================
Python 3.9.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /private
collected 8 items
test_advanced.py::test_str_to_bool_true[Y] PASSED [ 12%]
test_advanced.py::test_str_to_bool_true[y] PASSED [ 25%]
test_advanced.py::test_str_to_bool_true[1] PASSED [ 37%]
test_advanced.py::test_str_to_bool_true[YES] PASSED [ 50%]
test_advanced.py::test_str_to_bool_false[N] PASSED [ 62%]
test_advanced.py::test_str_to_bool_false[n] PASSED [ 75%]
test_advanced.py::test_str_to_bool_false[0] PASSED [ 87%]
test_advanced.py::test_str_to_bool_false[NO] PASSED [100%]
============================== 8 passed in 0.01s ===============================
雖然您只撰寫了兩個測試函式,但由於 pytest 函式,parametrize() 總共能夠建立八個測試。
步驟 3 - 將現有的測試移植到固件
將新的類別型測試新增至 test_advanced.py 檔案。 此測試應該使用
setup()和teardown()函式來建立暫存檔,其中包含一些文字。 每次測試之後,就會移除檔案。 其看起來應該如下:import os class TestFile: def setup(self): with open("/tmp/done", 'w') as _f: _f.write("1") def teardown(self): try: os.remove("/tmp/done") except OSError: pass def test_done_file(self): with open("/tmp/done") as _f: contents = _f.read() assert contents == "1"此測試類別會建立一個檔案,但有問題,因為 /tmp/ 路徑並不保證存在於每個系統上。
建立一個固件,其會使用
pytesttmpdir()裝置寫入至檔案並傳回路徑:import pytest @pytest.fixture def tmpfile(tmpdir): def write(): file = tmpdir.join("done") file.write("1") return file.strpath return writetmpfile()固件會使用 Pytest 的tmpdir()固件,其保證在測試完成之後會清除有效的暫存檔案。更新類別
TestFile,使其使用固件而非協助程式方法:class TestFile: def test_f(self, tmpfile): path = tmpfile() with open(path) as _f: contents = _f.read() assert contents == "1"這個測試類別現在確保系統會建立一個暫存檔案,且此檔案具有適當的內容,讓判斷提示能夠運作。
檢查您的工作
現在,您應該會有名為 test_advanced.py 的 Python 檔案,其中包含下列程式碼:
- 接受字串並視字串的內容傳回布林值的
str_to_bool()函式。 -
str_to_bool()函式的兩個參數化測試,一個測試True值,另一個測試False值。 - 自訂
pytest固件,其使用tmpdir()固件建立一個具有某些內容的暫存「完成」檔案。 - 使用自訂
tmpfile()固件來建立檔案的測試類別。
在終端機執行所有測試時,這些測試都應通過,沒有錯誤發生。