Learn
← Previous Next →

Hari 29: Testing, Debugging & Best Practices

65 min Last updated 26 Mar 2026

Mengapa Testing?

Testing memastikan kode bekerja sesuai harapan, mencegah bug saat ada perubahan, dan membuat kode lebih mudah di-refactor dengan percaya diri.

unittest — Testing Bawaan Python

import unittest

def bagi(a, b):
    if b == 0:
        raise ZeroDivisionError("Tidak bisa bagi nol")
    return a / b

def is_prima(n):
    if n < 2: return False
    for i in range(2, int(n**0.5)+1):
        if n % i == 0: return False
    return True

class TestMatematika(unittest.TestCase):

    def test_bagi_normal(self):
        self.assertEqual(bagi(10, 2), 5.0)

    def test_bagi_desimal(self):
        self.assertAlmostEqual(bagi(1, 3), 0.333, places=2)

    def test_bagi_nol_raises(self):
        with self.assertRaises(ZeroDivisionError):
            bagi(10, 0)

    def test_is_prima(self):
        prima = [2, 3, 5, 7, 11, 13, 17, 19, 23]
        bukan = [0, 1, 4, 6, 8, 9, 10, 15]
        for n in prima:
            self.assertTrue(is_prima(n))
        for n in bukan:
            self.assertFalse(is_prima(n))

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

pytest — Testing Modern (pip install pytest)

import pytest

def test_bagi_normal():
    assert bagi(10, 2) == 5.0

def test_bagi_nol():
    with pytest.raises(ZeroDivisionError):
        bagi(10, 0)

@pytest.mark.parametrize("n,expected", [
    (2, True), (3, True), (4, False), (17, True), (100, False),
])
def test_is_prima(n, expected):
    assert is_prima(n) == expected

# Jalankan: pytest test_file.py -v

Python Best Practices (PEP 8)

# Penamaan
MAX_NILAI  = 100              # UPPER_CASE untuk konstanta
nama_user  = "Budi"           # snake_case untuk variabel & fungsi
class SistemNilai: pass       # PascalCase untuk class

# Docstring
def hitung_rata(data: list) -> float:
    """Hitung rata-rata dari list angka.

    Args:
        data: list of int/float

    Returns:
        float: rata-rata nilai, 0.0 jika list kosong
    """
    return sum(data) / len(data) if data else 0.0

# Hindari magic number
PASSING_GRADE = 70            # beri nama yang bermakna
if nilai >= PASSING_GRADE:
    print("Lulus")

Type Hints (Python 3.5+)

from typing import List, Dict, Optional, Tuple

def sapa(nama: str, salam: str = "Halo") -> str:
    return f"{salam}, {nama}!"

def statistik(data: List[float]) -> Dict[str, float]:
    return {"min": min(data), "max": max(data), "avg": sum(data)/len(data)}

def cari_user(user_id: int) -> Optional[Dict]:
    ...  # None jika tidak ditemukan

# Jalankan type checking: pip install mypy && mypy script.py

Debugging

# breakpoint() — Python 3.7+
def cari_bug(data):
    hasil = 0
    for i, n in enumerate(data):
        breakpoint()     # berhenti di sini, bisa inspect variabel
        hasil += n * i
    return hasil

# Perintah pdb: n(ext), s(tep), c(ontinue), p expr, l(ist), q(uit)

# Cara sederhana: print debugging
def proses(data):
    print(f"[DEBUG] Input: {data}")   # tambah sementara
    hasil = sorted(data)
    print(f"[DEBUG] Sorted: {hasil}")
    return hasil

Assignment

Buat test lengkap untuk class RekeningBank menggunakan unittest. Uji: saldo awal, deposit normal, deposit negatif (ValueError), tarik normal, tarik melebihi saldo (ValueError), dan konstruktor dengan saldo negatif (ValueError).

Expected output:

test_deposit_negatif_raises ... ok
test_deposit_nol_raises ... ok
test_deposit_normal ... ok
test_konstruktor_saldo_negatif ... ok
test_saldo_awal ... ok
test_tarik_melebihi_saldo_raises ... ok
test_tarik_normal ... ok
------
Ran 7 tests in 0.001s
OK
PY main.py
Solution
Output