Python

Panduan Belajar Python: Testing di Python

Language

Panduan ini untuk siapa

  • Pembelajar yang menulis script multi-function dan aplikasi kecil
  • Developer yang ingin rasa percaya diri sebelum refactor atau rilis
  • Tim yang membutuhkan verifikasi berulang di lingkungan lokal dan CI

Apa yang akan Anda pelajari

  • Perbedaan unittest, doctest, dan pytest
  • Cara menulis test yang mudah dibaca dengan assertions dan fixtures
  • Cara menjalankan test lintas environment dengan tox
  • Cara mengukur test coverage dengan coverage.py
  • Mindset inti TDD untuk development yang bertahap dan andal

Mengapa topik ini penting

Testing melindungi kode Anda dari regresi dan memberi kepercayaan diri untuk memperbaiki desain dari waktu ke waktu. Tanpa test, bahkan edit kecil bisa memunculkan bug diam-diam yang sulit dideteksi manual.

Di Python, Anda bisa mulai sederhana dan meningkatkan secara bertahap. Beberapa test yang tepat sering menangkap kegagalan paling mahal lebih awal dan memudahkan kolaborasi.

Konsep inti

Jenis test dan framework

  • unittest: bawaan dan terstruktur
  • pytest: populer, ringkas, ekosistem plugin kaya
  • doctest: memvalidasi contoh di docstring

Contoh unittest (secara historis juga disebut pyunit):

import unittest


def multiply(a, b):
	return a * b


class TestMultiply(unittest.TestCase):
	def test_multiply(self):
		self.assertEqual(multiply(3, 4), 12)


if __name__ == "__main__":
	unittest.main()

Contoh test pytest sederhana:

def add(a, b):
	return a + b


def test_add():
	assert add(2, 3) == 5

Test yang mudah dibaca sebaiknya menjelaskan behavior, bukan detail implementasi.

Pola Arrange-Act-Assert

Sebagian besar unit test mengikuti tiga langkah:

  • Arrange state input
  • Act dengan memanggil function
  • Assert output yang diharapkan
def test_discount_price():
	price = 100
	discount = 0.2
	result = price * (1 - discount)
	assert result == 80

Struktur ini membuat test konsisten dan mudah dibaca.

Coverage dan confidence

Coverage memberi tahu seberapa banyak kode yang dieksekusi saat testing. Ini sinyal, bukan jaminan.

python -m pip install coverage
coverage run -m pytest
coverage report -m

Coverage tinggi berguna, tetapi assertion yang bermakna lebih penting daripada persentase.

Panduan langkah demi langkah

Langkah 1 — Buat module yang mudah diuji

Buat calculator.py:

def divide(a: float, b: float) -> float:
	if b == 0:
		raise ValueError("b must not be zero")
	return a / b

Function kecil yang murni paling mudah untuk diuji.

Langkah 2 — Tambahkan test pytest

Buat test_calculator.py:

import pytest
from calculator import divide


def test_divide_success():
	assert divide(10, 2) == 5


def test_divide_by_zero():
	with pytest.raises(ValueError):
		divide(10, 0)

Jalankan test:

pytest -q

Langkah 3 — Tambahkan coverage dan cek lintas environment

coverage run -m pytest
coverage report -m

Konfigurasi tox opsional (untuk cek multi-versi):

[tox]
envlist = py311, py312

[testenv]
deps = pytest
commands = pytest

Ini membantu memverifikasi behavior pada versi Python yang didukung.

Struktur project pytest sederhana:

my_project/
├── src/
│   └── calculator.py
├── tests/
│   └── test_calculator.py
├── pyproject.toml
└── README.md

Contoh praktis

Contoh 1 — Parameterized tests untuk banyak input

import pytest


@pytest.mark.parametrize(
	"a,b,expected",
	[
		(1, 2, 3),
		(10, 5, 15),
		(-1, 1, 0),
	],
)
def test_add_cases(a, b, expected):
	assert a + b == expected

Expected result:

3 passed

Contoh 2 — Doctest untuk dokumentasi yang dapat dieksekusi

def square(value: int) -> int:
	"""
	Return square of a number.

	>>> square(4)
	16
	>>> square(-3)
	9
	"""
	return value * value

Jalankan doctest:

python -m doctest -v your_module.py

Ini menjaga contoh dan behavior tetap selaras.

Contoh 3 — Siklus mini TDD (Red -> Green -> Refactor)

Mulai dengan menulis test yang gagal (Red):

def test_is_even():
	assert is_even(4) is True
	assert is_even(5) is False

Lalu implementasikan kode minimal agar lulus (Green):

def is_even(value):
	return value % 2 == 0

Terakhir, perbaiki nama/struktur tanpa merusak test (Refactor).

Expected result:

  • Test lulus setelah implementasi, dan tetap lulus setelah refactor yang aman.

Kesalahan umum dan cara menghindarinya

  • Menulis test hanya untuk happy path -> Tambahkan edge case dan failure case.
  • Terlalu banyak assertion dalam satu test -> Jaga test tetap fokus pada satu behavior.
  • Mengikat test ke detail implementasi internal -> Uji behavior publik, bukan internal privat.
  • Menjadikan persentase coverage sebagai kualitas absolut -> Kombinasikan coverage dengan assertion bermakna.

Latihan cepat

  • Tulis test untuk function safe_divide(a, b) termasuk penanganan pembagian nol.
  • Ubah satu pola test berulang menjadi pytest.mark.parametrize.
  • Buat coverage report dan identifikasi satu branch yang belum diuji untuk ditingkatkan.

Ringkasan utama

  • Test adalah safety net yang mempercepat development dan refactor.
  • pytest menawarkan default praktis untuk banyak tim Python.
  • Coverage adalah panduan yang berguna tetapi tidak menggantikan desain test yang matang.
  • Test kecil dengan ruang lingkup jelas memberi nilai jangka panjang tertinggi.

Langkah berikutnya

Lanjut ke Dokumentasi. Di panduan berikutnya, Anda akan menulis dokumentasi yang mudah dirawat dengan docstrings, Sphinx, dan workflow MkDocs.

No Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.