Hai, teman-teman! Coba bayangin kamu baru selesai menulis validasi form pendaftaran, lengkap dengan test-nya. Datanya satu orang: Budi Santoso, budi@example.com, lahir 1998. Test-nya lolos, hijau semua:
1 passed in 0.23s
Masalahnya, nama Budi hanya satu dari sekian banyak variasi nama di dunia nyata. Nama pendaftar sungguhan macam-macam, begitu juga cara mereka menulis nomor telepon. Kalau ingin menulis semua variasi itu satu per satu, jelas tidak mungkin, apalagi variasi yang belum terpikir sama sekali. Jadi kita serahkan masalah ini ke library Faker: biarkan ia membuat 100 pendaftar yang berbeda-beda. Di pytest caranya pendek, cukup tambahkan parameter faker ke fungsi test. Ternyata, begitu Budi diganti dengan data pendaftar dari Faker, pendaftar pertama langsung ditolak:
AssertionError: {'nama': 'drg. Vanya Andriani, S.Gz', 'email': 'calista76@example.com', 'telepon': '+62 (938) 242-1948', 'tanggal_lahir': datetime.date(1993, 10, 17)}
Validatornya menolak nama bergelar. Padahal di dunia nyata, orang bergelar mendaftar setiap hari. Di bagian 6 ini kita pakai Faker di pytest untuk menemukan bug seperti ini sebelum pengguna sungguhan yang menemukannya.
TL;DR: Faker otomatis menyediakan fixture faker untuk pytest. Bawaannya memakai locale en_US, di-seed ulang dengan 0 sebelum setiap test, dan ingatan unique-nya dikosongkan. Locale diubah lewat fixture faker_session_locale di conftest.py, dan seed lewat faker_seed. Karena seed selalu di-reset, test parametrize mendapat data yang sama persis, kecuali kita memanggil faker.seed_instance(). Dari pendaftar dummy pertama saja, dua masalah di validator langsung ketahuan.
Kenalan Dulu: Fixture faker di pytest
Parameter faker tadi adalah sebuah fixture. Fixture adalah data atau object yang disiapkan pytest untuk sebuah test. Cara memakainya cukup dengan menulis nama fixture sebagai parameter fungsi test. Faker mendaftarkan fixture bernama faker secara otomatis begitu Faker terpasang di environment yang sama dengan pytest.
Artikel ini menganggap kamu sudah pernah menulis dan menjalankan test dengan pytest. Kalau belum, baca dulu Pytest Itu Apa? Cara Install, Menulis, dan Running Test di Python, yang juga membahas fixture, conftest.py, dan parametrize dari dasar. Kalau belum punya pytest, pasang dulu:
pip install pytest faker
Contoh di artikel ini diuji dengan pytest 9.1.1, Faker 40.43.0, dan Python 3.14. Kamu tidak perlu import faker di file test. Faker mendaftarkan fixture-nya ke pytest sebagai plugin, jadi cukup tulis faker sebagai parameter:
def test_pertama(faker):
print("\ntest_pertama:", faker.name())
def test_kedua(faker):
print("\ntest_kedua:", faker.name())
Jalankan dengan pytest -s supaya hasil print ikut tampil:
test_pertama: Norma Fisher
.
test_kedua: Norma Fisher
.
2 passed in 0.40s
Ada dua hal yang langsung terlihat. Namanya nama Amerika, padahal kita butuh data Indonesia. Kedua test juga mendapat nama yang sama persis. Dua-duanya bukan kebetulan, tapi perilaku bawaan yang tertulis di dokumentasi Pytest Fixtures Faker:
- Fixture
fakermemakai satu object Faker untuk seluruh sesi test, dengan locale bawaanen_US. - Sebelum setiap test, object itu di-seed ulang dengan angka 0, jadi setiap test mulai dari urutan acak yang sama.
- Ingatan
fake.uniquedari bagian 4 ikut dikosongkan sebelum setiap test.
Seed yang selalu sama ini sebenarnya disengaja. Test yang gagal hari ini akan gagal dengan data yang sama besok, jadi bug-nya bisa diulang dan dicari.
Mengatur Locale dan Seed Lewat conftest.py
Locale dan seed fixture faker diatur lewat dua fixture khusus di conftest.py: faker_session_locale untuk locale, dan faker_seed untuk angka seed. Keduanya ditulis dengan scope="session" dan autouse=True, supaya berlaku untuk semua test di folder itu tanpa perlu disebut satu per satu. autouse=True di sini wajib, bukan sekadar praktis. Alasannya dibahas sebentar lagi.
conftest.py adalah file khusus pytest. Fixture yang ditulis di situ otomatis tersedia untuk semua file test di folder yang sama dan di bawahnya, tanpa import. Penjelasan lengkapnya ada di panduan fixture pytest.
import pytest
from nik_provider import NikProvider
@pytest.fixture(scope="session", autouse=True)
def faker_session_locale():
return ["id_ID"]
@pytest.fixture(autouse=True)
def tambah_provider(faker):
faker.add_provider(NikProvider)
Fixture kedua, tambah_provider, mendaftarkan NikProvider dari bagian 5 ke object faker sebelum setiap test. Jadi faker.nik() bisa langsung dipakai di test mana pun.
Kalau mau seed selain 0, tambahkan fixture faker_seed dengan cara yang sama. Contohnya ada di jawaban tantangan di akhir artikel.
Dari Mana Object Faker-nya Datang?
Di luar pytest, object Faker kita buat sendiri dengan fake = Faker("id_ID"). Di conftest.py tadi tidak ada baris seperti itu. faker_session_locale juga tidak membuat object apa pun, ia hanya mengembalikan daftar locale. Lalu siapa yang membuat object-nya?
Jawabannya plugin pytest milik Faker. Saat pip install faker, Faker ikut mendaftarkan modul faker.contrib.pytest.plugin ke pytest, dan pytest memuat plugin seperti ini secara otomatis setiap kali dijalankan. Tandanya ada di bagian atas output pytest:
plugins: Faker-40.43.0
Perintah pytest --fixtures juga menunjukkan dari mana fixture faker berasal:
-------------- fixtures defined from faker.contrib.pytest.plugin --------------
faker -- ..\venv\Lib\site-packages\faker\contrib\pytest\plugin.py:24
Fixture that returns a seeded and suitable ``Faker`` instance.
Isi plugin itu pendek. Ini versi ringkasnya, tanpa docstring:
@pytest.fixture(scope="session", autouse=True)
def _session_faker(request):
if "faker_session_locale" in request.fixturenames:
locale = request.getfixturevalue("faker_session_locale")
else:
locale = [DEFAULT_LOCALE] # en_US
return Faker(locale=locale)
@pytest.fixture()
def faker(request):
if "faker_locale" in request.fixturenames:
locale = request.getfixturevalue("faker_locale")
fake = Faker(locale=locale)
else:
fake = request.getfixturevalue("_session_faker")
seed = DEFAULT_SEED # 0
if "faker_seed" in request.fixturenames:
seed = request.getfixturevalue("faker_seed")
fake.seed_instance(seed=seed)
fake.unique.clear()
return fake
Jadi Faker("id_ID")-nya tetap ada, hanya saja ditulis di dalam plugin. Fixture _session_faker membuat object Faker sekali untuk seluruh sesi test, dengan locale dari faker_session_locale. Fixture faker lalu men-seed ulang object itu dan mengosongkan ingatan unique-nya sebelum menyerahkannya ke test kita.
Supaya tidak cuma percaya pada kode orang, kita bandingkan isi fixture faker dengan object Faker buatan sendiri:
import pytest
from faker import Faker
def test_fixture_sama_dengan_faker_manual(faker):
fake = Faker("id_ID")
fake.seed_instance(0)
nama_fixture = faker.name()
nama_manual = fake.name()
print("\nfixture:", faker.locales, nama_fixture)
print("manual :", fake.locales, nama_manual)
assert nama_fixture == nama_manual
Plugin di atas juga memperlihatkan bahwa fixture pengaturnya hanya tiga:
| Fixture | Yang diatur | Kalau tidak ada |
|---|---|---|
faker_session_locale |
Locale object Faker yang dipakai bersama oleh seluruh test | en_US |
faker_locale |
Locale untuk test tertentu saja. Plugin membuat object Faker baru khusus untuk test itu | Memakai object milik sesi |
faker_seed |
Angka seed yang dipasang sebelum setiap test | 0 |
Dua fixture terakhir dicoba di file yang sama. Kali ini keduanya tidak memakai autouse, tapi diminta langsung sebagai parameter test:
@pytest.fixture
def faker_seed():
return 2026
@pytest.fixture
def faker_locale():
return ["de_DE"]
def test_seed_lain(faker, faker_seed):
print("\nfaker_seed :", faker.locales, faker.name())
def test_locale_lain(faker, faker_locale):
print("\nfaker_locale:", faker.locales, faker.name())
Hasil pytest 2_tests/test_1_asal_fixture.py -s -q:
fixture: ['id_ID'] drg. Vanya Andriani, S.Gz
manual : ['id_ID'] drg. Vanya Andriani, S.Gz
.
faker_seed : ['id_ID'] Galuh Mardhiyah
.
faker_locale: ['de_DE'] Nurten Linke-Benthin
.
3 passed in 0.85s
Fixture faker memberi nama yang sama persis dengan Faker("id_ID") yang di-seed 0. Test kedua tetap memakai locale id_ID dari sesi, tapi seed-nya 2026, jadi namanya lain. Test ketiga mendapat object baru dengan locale de_DE.
Ada satu hal penting di kode plugin tadi, yaitu pengecekan in request.fixturenames. Plugin hanya membaca fixture pengatur yang aktif untuk test tersebut, entah karena diminta sebagai parameter seperti di atas, atau karena ditandai autouse=True. Fixture yang hanya ditulis di conftest.py tanpa salah satu dari keduanya akan diabaikan diam-diam. Coba hapus autouse=True dari faker_session_locale di conftest.py, lalu jalankan lagi:
fixture: ['en_US'] Norma Fisher
manual : ['id_ID'] drg. Vanya Andriani, S.Gz
F
Tidak ada error atau peringatan soal locale. Locale-nya diam-diam kembali ke en_US, dan yang gagal hanya assert perbandingan kita. Tanpa test pembanding seperti ini, kesalahan itu baru ketahuan setelah kita heran kenapa datanya berisi nama Amerika.
Test dengan Data Faker: Bug Pertama Ketahuan
Yang kita uji adalah fungsi validasi_pendaftaran(). Fungsi ini menerima data satu pendaftar dan mengembalikan daftar kesalahan. Kalau daftarnya kosong, pendaftaran diterima. Ini versi awalnya:
import re
from datetime import date
def hitung_umur(tanggal_lahir, hari_ini):
belum_ulang_tahun = (hari_ini.month, hari_ini.day) < (tanggal_lahir.month, tanggal_lahir.day)
return hari_ini.year - tanggal_lahir.year - belum_ulang_tahun
def validasi_pendaftaran(data, hari_ini=None):
hari_ini = hari_ini or date.today()
kesalahan = []
if not re.fullmatch(r"[A-Za-z ]+", data["nama"]):
kesalahan.append("nama hanya boleh berisi huruf dan spasi")
if not re.fullmatch(r"[\w.+-]+@[\w-]+(\.[\w-]+)+", data["email"]):
kesalahan.append("format email tidak valid")
telepon = data.get("telepon")
if telepon is not None and not re.fullmatch(r"08\d{8,11}", telepon):
kesalahan.append("nomor telepon harus diawali 08 dan berisi 10-13 angka")
if hitung_umur(data["tanggal_lahir"], hari_ini) < 17:
kesalahan.append("umur minimal 17 tahun")
return kesalahan
Test dengan data tetap Budi Santoso lolos, karena Budi kebetulan tidak bergelar dan menulis teleponnya tanpa spasi.
Jadi kita minta Faker menyiapkan 100 pendaftar yang berbeda-beda. Pembuat datanya ditaruh di file terpisah, data_uji.py, supaya bisa dipakai banyak test:
def buat_pendaftar(fake):
return {
"nama": fake.name(),
"email": fake.email(),
"telepon": fake.optional.phone_number(prob=0.7),
"tanggal_lahir": fake.date_of_birth(minimum_age=17, maximum_age=80),
}
Test-nya:
from data_uji import buat_pendaftar
from pendaftaran_awal import validasi_pendaftaran
def test_pendaftar_faker_lolos(faker):
for _ in range(100):
data = buat_pendaftar(faker)
assert validasi_pendaftaran(data) == [], data
Bagian , data setelah assert adalah pesan yang ditampilkan kalau assert gagal. Tanpa pesan ini, pytest hanya bilang daftar kesalahannya tidak kosong, tanpa memberi tahu data mana yang membuatnya gagal. Hasilnya:
> assert validasi_pendaftaran(data) == [], data
E AssertionError: {'nama': 'drg. Vanya Andriani, S.Gz', 'email': 'calista76@example.com', 'telepon': '+62 (938) 242-1948', 'tanggal_lahir': datetime.date(1993, 10, 17)}
E assert ['nama hanya ... 10-13 angka'] == []
E
E Left contains 2 more items, first extra item: 'nama hanya boleh berisi huruf dan spasi'
Pendaftar pertama saja sudah membawa dua kesalahan sekaligus: nama bergelar dan telepon yang berformat. Ini bukan kasus langka. Test test_nama_bergelar_bawaan_faker di GitHub menghitungnya: dari 2.000 nama id_ID, 845 mengandung gelar atau tanda baca, seperti "Tgk. Patricia Suartini" dan "Belinda Sitompul, M.Kom.".
Jebakan: parametrize Mendapat Data yang Sama
Test berisi loop seperti di atas punya satu kelemahan: pytest berhenti di kegagalan pertama. Kalau ada 30 dari 100 pendaftar yang gagal, kita hanya melihat satu. Solusi yang biasa dipakai adalah pytest.mark.parametrize, yang mengubah satu test menjadi banyak test terpisah, masing-masing dengan laporan sendiri.
Tapi coba lihat apa yang terjadi kalau digabung dengan fixture faker:
@pytest.mark.parametrize("nomor", range(3))
def test_parametrize_tanpa_seed(faker, nomor):
print(f"\nnomor {nomor}:", faker.name())
nomor 0: drg. Vanya Andriani, S.Gz
.
nomor 1: drg. Vanya Andriani, S.Gz
.
nomor 2: drg. Vanya Andriani, S.Gz
.
Tiga test, tapi orangnya sama. Penyebabnya perilaku yang tadi: setiap test, termasuk setiap variasi parametrize, di-seed ulang dengan 0. Jadi 200 test hasil parametrize sebenarnya cuma menguji satu orang 200 kali, dan semuanya lolos atau gagal bersama-sama.
Perbaikannya, pakai angka nomor sebagai seed untuk test itu sendiri dengan faker.seed_instance(nomor):
@pytest.mark.parametrize("nomor", range(200))
def test_pendaftar_realistis_lolos(faker, nomor):
faker.seed_instance(nomor)
data = buat_pendaftar_realistis(faker)
assert validasi_pendaftaran(data) == [], data
Sekarang setiap test mendapat pendaftar yang berbeda, dan tetap bisa diulang. Test nomor 57 akan selalu memakai data yang sama setiap kali dijalankan.
Kode yang Salah atau Data yang Salah?
Saat test dengan data Faker gagal, ada dua kemungkinan. Bisa kodenya yang salah, karena menolak data yang wajar. Bisa juga datanya yang salah, karena Faker menghasilkan data yang tidak masuk akal untuk kasus kita. Dua kesalahan di pendaftar pertama tadi kebetulan mewakili keduanya.
Nama Bergelar: Kodenya yang Salah
Gelar seperti "Ir.", "S.Pd", dan "Hj." adalah bagian sah dari nama orang Indonesia. Validator yang hanya menerima huruf dan spasi jelas terlalu ketat, jadi kodenya yang diperbaiki:
# gelar seperti "Ir." dan "S.Pd" memakai titik dan koma
if not re.fullmatch(r"[A-Za-z][A-Za-z .,']*", data["nama"]):
kesalahan.append("nama hanya boleh berisi huruf, spasi, titik, koma, dan apostrof")
Nama sekarang harus diawali huruf, lalu boleh diikuti huruf, spasi, titik, koma, atau apostrof.
Nomor Telepon: Sebagian Kode, Sebagian Data
Untuk telepon, ceritanya lebih rumit. Orang memang sering menulis nomor dengan spasi, strip, atau awalan +62, jadi validator perlu menormalkan dulu sebelum mengecek:
def normalisasi_telepon(telepon):
# buang spasi, kurung, dan strip, lalu ubah +62 jadi 0
angka = re.sub(r"[\s()-]", "", telepon)
if angka.startswith("+62"):
angka = "0" + angka[3:]
return angka
Tapi setelah dinormalkan pun, kebanyakan nomor dari phone_number() tetap ditolak:
phone_number() yang bukan nomor seluler 08: 852 dari 1.000, contoh: ['(060) 487 6475', '+62 (0115) 781-5659', '+62-97-535-1393']
Kali ini datanya yang tidak cocok. phone_number() menghasilkan campuran nomor telepon rumah dan format yang tidak lazim, sedangkan form kita meminta nomor seluler. Bahkan ada format seperti +62 (0115), padahal menurut penjelasan penomoran telepon Indonesia, angka 0 di depan kode area selalu dihilangkan kalau nomor ditulis dengan +62.
Jadi pembuat datanya yang disesuaikan. Kita tulis sendiri beberapa format nomor seluler yang memang biasa dipakai, lalu biarkan numerify() mengisi angkanya:
FORMAT_SELULER = ("08##########", "08##-####-####", "08## #### ####", "+628##########")
def buat_pendaftar_realistis(fake):
tanggal_lahir = fake.date_of_birth(minimum_age=17, maximum_age=80)
return {
"nama": fake.name(),
"email": fake.email(),
"telepon": fake.optional.numerify(fake.random_element(FORMAT_SELULER), prob=0.7),
"tanggal_lahir": tanggal_lahir,
"nik": fake.nik(tanggal_lahir=tanggal_lahir),
}
Variasi spasi, strip, dan +62 tetap ada, jadi normalisasi_telepon() tetap teruji. Yang dibuang hanya format yang memang tidak mungkin muncul di kolom nomor seluler.
Versi ini juga menambah kolom nik dari NikProvider, dengan tanggal lahir yang sama. Validator versi akhir ikut mengecek bahwa tanggal lahir di NIK cocok dengan kolom tanggal_lahir, memakai bedah_nik() dari bagian 5.
Hasil Akhir: 203 Test Lolos
File test_4_pendaftaran.py berisi empat test:
- 200 pendaftar realistis yang harus lolos,
- satu test yang menghitung nama bergelar dari name(),
- satu test yang menghitung format phone_number() tadi,
- satu test yang memastikan NIK dengan tanggal lahir berbeda ditolak.
Semuanya dijalankan:
pytest 2_tests/test_4_pendaftaran.py -q
203 passed in 0.44s
Kalau seluruh folder 2_tests dijalankan, satu test tetap gagal, yaitu test_pendaftar_faker_lolos yang memakai validator versi awal. Test itu sengaja dibiarkan di repo sebagai bukti bug yang tadi ditemukan.
Test negatif juga penting. Validator yang menerima semua data akan meloloskan 200 pendaftar tadi tanpa masalah. Test NIK di atas memastikan validator masih bisa menolak data yang salah, dan dua tantangan di akhir artikel menambah test negatif lainnya.
Error yang Sering Muncul Saat Memakai Faker di pytest
Masalah yang paling sering muncul justru tidak menampilkan error sama sekali. Test-nya hijau, tapi datanya tidak menguji apa yang kita kira.
| Gejala | Penyebab | Perbaikan |
|---|---|---|
fixture 'faker' not found |
Faker belum terpasang di environment yang sama dengan pytest | pip install faker di environment yang menjalankan pytest |
| Data berisi nama dan alamat Amerika | Locale bawaan fixture faker adalah en_US |
Tambahkan fixture faker_session_locale yang mengembalikan ["id_ID"] di conftest.py |
Locale tetap en_US padahal faker_session_locale sudah ditulis |
Fixture ditulis tanpa autouse=True, jadi tidak pernah aktif dan plugin tidak membacanya |
Tambahkan autouse=True, atau minta fixture itu sebagai parameter test |
Locale berubah jadi en_US saat semua folder test dijalankan sekaligus |
Object Faker milik sesi dibuat sekali oleh test pertama yang membutuhkannya. Kalau test itu ada di folder tanpa faker_session_locale, seluruh sesi memakai en_US |
Taruh faker_session_locale di conftest.py paling atas, atau jalankan folder satu per satu |
Semua test parametrize mendapat data yang sama |
Fixture faker di-seed ulang dengan 0 sebelum setiap test |
Panggil faker.seed_instance(nomor) di awal test |
AttributeError: 'Generator' object has no attribute 'nik' |
Provider custom belum didaftarkan ke fixture faker |
Daftarkan lewat fixture autouse di conftest.py |
| Test berisi loop hanya melaporkan satu kegagalan | assert menghentikan test di data pertama yang gagal |
Pakai parametrize dengan seed_instance, dan beri pesan assert ..., data |
ModuleNotFoundError saat mengimpor modul yang diuji |
Folder proyek tidak ada di jalur import pytest | Tambahkan pythonpath = . di pytest.ini |
Baris terakhir muncul karena file test ada di subfolder, sedangkan pendaftaran.py ada di folder induk. Opsi pythonpath dijelaskan di halaman konfigurasi pytest.
Tantangan untuk Kamu
Coba kerjakan dulu sebelum membuka jawabannya. Jawaban keempatnya ada di folder 3_tantangan di GitHub, dengan conftest.py sendiri.
Tantangan 1. Buat 50 test yang memastikan pendaftar berumur di bawah 17 tahun selalu ditolak.
@pytest.mark.parametrize("nomor", range(50))
def test_umur_di_bawah_17_ditolak(faker, nomor):
faker.seed_instance(nomor)
data = buat_pendaftar_realistis(faker)
data["tanggal_lahir"] = faker.date_of_birth(minimum_age=10, maximum_age=16)
data["nik"] = None
assert "umur minimal 17 tahun" in validasi_pendaftaran(data)
Kolom nik dikosongkan, karena NIK-nya dibuat dari tanggal lahir lama dan pasti tidak cocok dengan tanggal lahir yang baru. Tanpa itu, test tetap lolos, tapi daftar kesalahannya berisi dua hal sekaligus. Test negatif yang baik hanya menguji satu kesalahan.
Tantangan 2. Buat test yang memastikan email tanpa tanda @ selalu ditolak. Petunjuk: faker.user_name() menghasilkan nama pengguna tanpa @.
def test_email_tanpa_at_ditolak(faker):
for _ in range(100):
data = buat_pendaftar_realistis(faker)
data["email"] = faker.user_name()
assert "format email tidak valid" in validasi_pendaftaran(data), data["email"]
Di sini loop biasa sudah cukup, karena yang diharapkan sama untuk semua data: ditolak. Kalau ada satu yang lolos, pesan assert langsung menunjukkan email mana.
Tantangan 3. Ubah seed fixture faker menjadi 2026 untuk semua test di satu folder, lalu buktikan namanya berbeda dari test dengan seed 0.
# conftest.py
@pytest.fixture(scope="session", autouse=True)
def faker_seed():
return 2026
# test_tantangan.py
def test_seed_2026(faker):
print("\nseed 2026:", faker.name())
seed 2026: Galuh Mardhiyah
Dengan seed 0, nama pertama dari locale id_ID adalah "drg. Vanya Andriani, S.Gz". Dengan seed 2026, namanya berubah, tapi tetap sama setiap kali test dijalankan.
Tantangan 4. Formulir pendaftaran ini ternyata juga dibuka untuk WNA. Uji validator versi perbaikan dengan nama dari locale id_ID, de_DE, dan fr_FR sekaligus, lalu hitung berapa nama dari tiap locale yang ditolak. Petunjuk: faker_locale boleh mengembalikan lebih dari satu locale, dan faker["de_DE"] memilih satu locale tertentu.
# test_tantangan.py
@pytest.fixture
def faker_locale():
return OrderedDict([("id_ID", 3), ("de_DE", 1), ("fr_FR", 1)])
def test_nama_pendaftar_wna(faker, faker_locale):
print("\ncampuran:", [faker.name() for _ in range(5)])
ditolak = {}
for locale in faker.locales:
ditolak[locale] = []
for _ in range(500):
data = buat_pendaftar_realistis(faker["id_ID"])
data["nama"] = faker[locale].name()
if any(k.startswith("nama") for k in validasi_pendaftaran(data)):
ditolak[locale].append(data["nama"])
print(f"{locale}: {len(ditolak[locale])} dari 500 ditolak, contoh {ditolak[locale][:3]}")
assert ditolak["id_ID"] == []
campuran: ['Dr. Marsudi Jailani', 'Hugues Gaudin', 'Caroline de la Brunel', 'Giuseppe Paffrath', 'Drs. Zaenab Lestari']
id_ID: 0 dari 500 ditolak, contoh []
de_DE: 179 dari 500 ditolak, contoh ['Bertold Hövel', 'Univ.Prof. Frederike Häring MBA.', 'Natascha Peukert-Schweitzer']
fr_FR: 225 dari 500 ditolak, contoh ['Sabine-Isabelle Bernard', 'Jeannine Lévêque', 'Luce Hervé-Albert']
53 passed in 0.79s
Kalau faker_locale berisi lebih dari satu locale, Faker masuk mode multi-locale. Setiap panggilan faker.name() memilih salah satu locale secara acak. Karena locale-nya ditulis dalam OrderedDict, peluangnya mengikuti bobot 3:1:1, atau 60, 20, dan 20 persen, seperti yang terlihat di daftar campuran. Sementara itu, faker["de_DE"] selalu memakai locale de_DE. Data lain dibuat lewat faker["id_ID"], karena hanya locale itu yang punya method nik().
Hasilnya, validator versi perbaikan masih menolak nama bertanda hubung dan berhuruf aksen. Pola [A-Za-z] hanya mengenal huruf tanpa aksen. Assert-nya sengaja hanya untuk id_ID, sedangkan locale lain dicetak sebagai temuan. Mau menerima nama WNA atau tidak adalah keputusan produk, bukan keputusan test. Kalau jawabannya mau, pola nama perlu dilonggarkan, lalu assert untuk de_DE dan fr_FR ditambahkan.
Ada satu jebakan. Di mode multi-locale, fixture tambah_provider di conftest.py langsung error:
NotImplementedError: Proxying calls to `add_provider` is not implemented in multiple locale mode.
Jadi provider dipasang ke satu locale saja. Untuk object Faker dengan satu locale, faker["id_ID"] adalah object itu sendiri, jadi test lain di folder ini tidak terganggu:
# conftest.py
@pytest.fixture(autouse=True)
def tambah_provider(faker):
faker["id_ID"].add_provider(NikProvider)
Penutup
Yang paling berharga dari bagian ini bukan fixture-nya, tapi kebiasaan yang muncul setelah test gagal. Setiap kegagalan memaksa kita bertanya: apakah kodenya yang terlalu ketat, atau datanya yang tidak masuk akal? Nama bergelar menjawab yang pertama, nomor +62 (0115) menjawab yang kedua. Dua-duanya tidak akan ketahuan dari satu data Budi Santoso.
Artikel berikutnya adalah Faker Python Series 7: Isi Database SQLite dan Analisis dengan pandas. Kita naik dari satu tabel ke dua tabel yang saling berelasi, mengisinya dengan puluhan ribu baris, lalu melihat apakah data dummy-nya cukup realistis untuk dianalisis.
Daftar semua artikel seri ini ada di label Faker Python. Coba jalankan fixture faker ke salah satu validator di proyekmu sendiri. Kalau ada test yang gagal, ceritakan di kolom komentar: kodenya yang salah, atau datanya?
Source code lengkap artikel ini bisa dilihat di GitHub: 06-faker-pytest
FAQ
Bagaimana cara memakai Faker di pytest?
Pasang Faker di environment yang sama dengan pytest, lalu tulis faker sebagai parameter fungsi test. Faker otomatis mendaftarkan fixture itu ke pytest sebagai plugin, jadi tidak perlu import. Fixture faker berisi object Faker yang siap dipakai, misalnya faker.name().
Kenapa fixture faker menghasilkan data bahasa Inggris?
Karena locale bawaan fixture faker adalah en_US. Untuk data Indonesia, buat fixture faker_session_locale dengan scope="session" dan autouse=True di conftest.py, lalu kembalikan ["id_ID"].
Kenapa setiap test pytest mendapat data Faker yang sama?
Fixture faker di-seed ulang dengan angka 0 sebelum setiap test, supaya hasilnya bisa diulang. Akibatnya, semua variasi parametrize juga mendapat data yang sama. Panggil faker.seed_instance(nomor) di awal test supaya setiap variasi mendapat data berbeda.
Bagaimana cara mengubah seed fixture faker?
Buat fixture faker_seed di conftest.py yang mengembalikan angka seed yang diinginkan, misalnya 2026. Kalau ditulis dengan scope="session" dan autouse=True, seed itu berlaku untuk semua test di folder tersebut.
Apa yang harus dilakukan kalau test dengan data Faker gagal? Cek dulu apakah datanya wajar untuk kasus yang diuji. Kalau wajar, seperti nama bergelar, berarti kodenya yang perlu diperbaiki. Kalau tidak wajar, seperti nomor telepon rumah untuk kolom nomor seluler, sesuaikan pembuat datanya.
Referensi
- Pytest Fixtures, Dokumentasi Faker, diakses 22 Oktober 2026
- How to use fixtures, Dokumentasi pytest, diakses 22 Oktober 2026
- How to parametrize fixtures and test functions, Dokumentasi pytest, diakses 22 Oktober 2026
- Configuration, Dokumentasi pytest, diakses 22 Oktober 2026
- pytest di PyPI, diakses 22 Oktober 2026
- Telephone numbers in Indonesia, Wikipedia, diakses 22 Oktober 2026


Posting Komentar untuk "Faker Python Series 6: Faker di pytest dengan Fixture faker"