Latihan
Dalam latihan ini, Anda akan menggunakan pytest dengan @pytest.mark.parametrize untuk menguji fungsi, termasuk kasus yang mengharapkan pengecualian. Kemudian, Anda akan merefaktor pengujian berbasis kelas dengan pendekatan gaya xUnit menggunakan setup_method() dan teardown_method() ke suatu fixture. Menggunakan parametrisasi dan konfigurasi awal membantu Anda menulis pengujian yang mencakup lebih banyak kasus dengan lebih sedikit pengulangan dan penyiapan yang lebih jelas.
Untuk bantuan penyiapan, lihat dokumentasi Python untuk lingkungan virtual, dokumentasi pip untuk pip install, dan dokumentasi pytest untuk menginstal pytest. Untuk detail selengkapnya tentang fitur pytest dalam latihan ini, lihat dokumentasi pytest untuk fungsi pengujian parametrizing, pernyataan tentang pengecualian yang diharapkan, perlengkapan, penyiapan gaya xUnit, dan direktori dan file sementara.
Sebelum Anda mulai
Gunakan Python 3.10 atau yang lebih baru, seperti yang dijelaskan dalam prasyarat modul. Jika Anda sudah memiliki lingkungan virtual dengan pytest yang diinstal dan diaktifkan, lanjutkan ke Langkah 1. Jika tidak, buat dan aktifkan lingkungan virtual di folder tempat Anda akan membuat test_advanced.py.
Pada Windows PowerShell:
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install pytest
python -m pytest --version
Di macOS, Linux, atau Subsistem Windows untuk Linux:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install pytest
python -m pytest --version
Perintah versi harus mencetak versi pytest, mirip dengan output ini:
pytest x.y.z
Perintah instal tidak menyematkan pytest ke versi tertentu. Pip menggunakan metadata paket untuk memilih rilis pytest stabil yang kompatibel dengan versi Python di lingkungan virtual.
Gunakan python -m pytest selama latihan ini agar pytest berjalan dari lingkungan aktif. Jika Windows PowerShell memblokir Activate.ps1, lihat dokumentasi Python venv untuk opsi kebijakan eksekusi PowerShell, atau jalankan Python lingkungan virtual secara langsung untuk perintah pip dan pytest. Contohnya:
.\.venv\Scripts\python -m pip install --upgrade pip
.\.venv\Scripts\python -m pip install pytest
.\.venv\Scripts\python -m pytest -v test_advanced.py
Langkah 1 - Tambahkan file dengan pengujian untuk latihan ini
Di folder yang sama tempat Anda akan menjalankan pytest, buat file pengujian baru bernama test_advanced.py. Jangan letakkan file di dalam folder .venv . Tambahkan kode berikut:
import pytest def str_to_bool(string): normalized = string.lower() if normalized in ["yes", "y", "1"]: return True if normalized in ["no", "n", "0"]: return False raise ValueError(f"Cannot convert {string!r} to a boolean")Fungsi
str_to_bool()menerima string sebagai input. Ini mengembalikanTrueuntuk nilai true yang dikenali, mengembalikanFalseuntuk nilai false yang dikenali, dan menaikkanValueErroruntuk nilai lainnya.Di file yang sama, tambahkan pengujian untuk fungsi
str_to_bool(). Gunakan@pytest.mark.parametrizeuntuk menguji nilai benar terlebih dahulu:@pytest.mark.parametrize("string", ["Y", "y", "1", "YES"]) def test_str_to_bool_true(string): assert str_to_bool(string) is TrueSelanjutnya, tambahkan pengujian lain dengan nilai false:
@pytest.mark.parametrize("string", ["N", "n", "0", "NO"]) def test_str_to_bool_false(string): assert str_to_bool(string) is FalseSekarang ada dua fungsi pengujian yang mencakup input representatif untuk kedua nilai pengembalian
TruedanFalse.Terakhir, tambahkan pengujian parametris untuk nilai yang tidak boleh diterima fungsi. Gunakan
pytest.raises()sebagai manajer konteks sehingga pengujian hanya lolos saatstr_to_bool()menaikkan pengecualian yang diharapkan:@pytest.mark.parametrize("string", ["maybe", "2"]) def test_str_to_bool_invalid(string): with pytest.raises(ValueError, match="Cannot convert"): str_to_bool(string)Argumen
matchmemeriksa pesan pengecualian dengan ekspresi reguler. Di sini, pengujian hanya memeriksa bagian stabil pesan sehingga tidak bergantung pada nilai yang persis tidak valid.
Catatan
Untuk kesederhanaan, latihan ini menyimpan kode yang sedang diuji dan tes dalam file yang sama. Dalam proyek Python nyata, kode aplikasi dan pengujian biasanya dipisahkan menjadi file dan direktori yang berbeda, seperti paket src/ dan direktori tests/.
Langkah 2 - Jalankan pengujian dan jelajahi laporan
Setelah Anda menambahkan pengujian, jalankan pytest dan periksa output. Gunakan bendera verbositas yang ditingkatkan (-v) sehingga Anda dapat melihat setiap nilai input yang diperlakukan sebagai pengujian terpisah.
Pada Windows PowerShell:
python -m pytest -v test_advanced.py
Di macOS, Linux, atau Subsistem Windows untuk Linux:
python -m pytest -v test_advanced.py
Output harus mirip dengan laporan berikut:
============================= test session starts ==============================
platform ... -- Python 3.x.y, pytest-x.y.z, pluggy-x.y.z -- ...
rootdir: ...
...
collected 10 items
test_advanced.py::test_str_to_bool_true[Y] PASSED [ 10%]
test_advanced.py::test_str_to_bool_true[y] PASSED [ 20%]
test_advanced.py::test_str_to_bool_true[1] PASSED [ 30%]
test_advanced.py::test_str_to_bool_true[YES] PASSED [ 40%]
test_advanced.py::test_str_to_bool_false[N] PASSED [ 50%]
test_advanced.py::test_str_to_bool_false[n] PASSED [ 60%]
test_advanced.py::test_str_to_bool_false[0] PASSED [ 70%]
test_advanced.py::test_str_to_bool_false[NO] PASSED [ 80%]
test_advanced.py::test_str_to_bool_invalid[maybe] PASSED [ 90%]
test_advanced.py::test_str_to_bool_invalid[2] PASSED [100%]
============================== 10 passed in 0.01s ==============================
Sistem operasi Anda, versi Python, versi pytest, jalur yang dapat dieksekusi, direktori akar, baris plugin dan cache, pemformatan kemajuan koleksi, pembungkusan baris, dan waktu proses mungkin berbeda. Meskipun Anda hanya menulis tiga fungsi pengujian, pytest mengumpulkan 10 pengujian karena setiap nilai input parametris berjalan sebagai kasus pengujiannya sendiri.
Langkah 3 - Refactor setup dan teardown menjadi sebuah fixture
Tambahkan pengujian berbasis kelas ke file test_advanced.py . Pengujian ini menggunakan metode xUnit dengan gaya
setup_method()danteardown_method()untuk membuat dan menghapus file dalam setiap metode pengujian.from pathlib import Path class TestFile: def setup_method(self): self.path = Path("done") self.path.write_text("1", encoding="utf-8") def teardown_method(self): self.path.unlink(missing_ok=True) def test_done_file(self): contents = self.path.read_text(encoding="utf-8") assert contents == "1"Pengujian ini dapat lulus, tetapi menulis nama file tetap di direktori kerja saat ini dan memerlukan kode pembersihan terpisah. Jika pengujian terganggu atau dijalankan bersamaan, seperti dengan
pytest-xdistatau tumpang tindih pengujian lokal, pendekatan ini dapat meninggalkan file usang, menimpa file yang sudah ada dengan nama selesai, atau menyebabkan pengujian saling memengaruhi satu sama lain.Tambahkan fixture tingkat modul yang menggunakan fixture bawaan
tmp_pathuntuk membuat file sementara. Pada langkah berikutnya, Anda akan memperbarui kelas untuk menggunakan fixture ini alih-alih metode penyiapan dan pembongkaran. Untuk keterbacaan, letakkan perlengkapan tingkat modul ini setelah pengujian parametrisstr_to_booldan sebelum kelasTestFile. Pytest menemukan fixture tingkat modul tanpa mempedulikan di mana fixture tersebut muncul dalam modul, sehingga posisinya ditujukan untuk pembaca manusia, bukan pytest.@pytest.fixture def tmp_file(tmp_path): def write(): path = tmp_path / "done" path.write_text("1", encoding="utf-8") return path return writeFitur
tmp_file()ini menggunakan fitur pytesttmp_pathyang menyediakan direktori unik sementarapathlib.Pathuntuk setiap pemanggilan fungsi pengujian, termasuk setiap kasus yang diparameterkan. Pytest mengelola direktori sementara, sehingga pengujian tidak bergantung pada jalur file yang dikodekan secara permanen.Hapus kelas sebelumnya
TestFile, termasuk metodesetup_method()danteardown_method(), dan ganti dengan versi akhir ini yang menggunakan perkakas alih-alih metode penyiapan dan teardown.class TestFile: def test_done_file(self, tmp_file): path = tmp_file() contents = path.read_text(encoding="utf-8") assert contents == "1"Anda juga dapat menghapus
from pathlib import Pathimpor yang Anda tambahkan pada langkah sebelumnya, karena pengujian tidak lagi membuat objekPathsecara langsung.
Periksa pekerjaan Anda
Sekarang Anda harus memiliki file Python bernama test_advanced.py yang berisi:
- Fungsi
str_to_bool()yang menerima string dan mengembalikan nilai boolean untuk nilai true dan false yang dikenali. - Tiga pengujian parametrik untuk fungsi
str_to_bool(): satu yang menguji nilaiTrue, satu yang menguji nilaiFalse, dan yang memeriksa nilai tidak valid yang memicuValueError. - Fixture pytest kustom yang menggunakan fixture bawaan
tmp_pathuntuk membuat file sementara done dengan beberapa konten. - Satu
TestFilekelas dengan satu metode yang menggunakan fixture kustomtmp_fileuntuk membuat dan membaca file. - Tidak ada
from pathlib import Pathmetode impor dan tidak adasetup_method()/teardown_method()dalam versi akhir.
File akhir akan terlihat mirip dengan yang berikut ini:
import pytest
def str_to_bool(string):
normalized = string.lower()
if normalized in ["yes", "y", "1"]:
return True
if normalized in ["no", "n", "0"]:
return False
raise ValueError(f"Cannot convert {string!r} to a boolean")
@pytest.mark.parametrize("string", ["Y", "y", "1", "YES"])
def test_str_to_bool_true(string):
assert str_to_bool(string) is True
@pytest.mark.parametrize("string", ["N", "n", "0", "NO"])
def test_str_to_bool_false(string):
assert str_to_bool(string) is False
@pytest.mark.parametrize("string", ["maybe", "2"])
def test_str_to_bool_invalid(string):
with pytest.raises(ValueError, match="Cannot convert"):
str_to_bool(string)
@pytest.fixture
def tmp_file(tmp_path):
def write():
path = tmp_path / "done"
path.write_text("1", encoding="utf-8")
return path
return write
class TestFile:
def test_done_file(self, tmp_file):
path = tmp_file()
contents = path.read_text(encoding="utf-8")
assert contents == "1"
Jalankan file pengujian lagi.
Pada Windows PowerShell:
python -m pytest -v test_advanced.py
Di macOS, Linux, atau Subsistem Windows untuk Linux:
python -m pytest -v test_advanced.py
Laporan akhir harus menunjukkan 11 tes yang dikumpulkan: 10 kasus dari tes parametris dan satu pengujian berbasis kelas.
============================= test session starts ==============================
platform ... -- Python 3.x.y, pytest-x.y.z, pluggy-x.y.z -- ...
rootdir: ...
...
collected 11 items
test_advanced.py::test_str_to_bool_true[Y] PASSED [ 9%]
test_advanced.py::test_str_to_bool_true[y] PASSED [ 18%]
test_advanced.py::test_str_to_bool_true[1] PASSED [ 27%]
test_advanced.py::test_str_to_bool_true[YES] PASSED [ 36%]
test_advanced.py::test_str_to_bool_false[N] PASSED [ 45%]
test_advanced.py::test_str_to_bool_false[n] PASSED [ 54%]
test_advanced.py::test_str_to_bool_false[0] PASSED [ 63%]
test_advanced.py::test_str_to_bool_false[NO] PASSED [ 72%]
test_advanced.py::test_str_to_bool_invalid[maybe] PASSED [ 81%]
test_advanced.py::test_str_to_bool_invalid[2] PASSED [ 90%]
test_advanced.py::TestFile::test_done_file PASSED [100%]
============================== 11 passed in 0.01s ==============================
Semua pengujian harus lulus tanpa kesalahan.