Pengujian dengan Bantuan AI: Menggunakan Pintu Pengawal Pengujian Unit untuk Menangkap Risiko Kode Dihasilkan AI

Membagikan alur kerja lengkap pengujian dengan bantuan AI, dari dokumen desain hingga kode kasus uji, menggunakan pintu pengawal pengujian unit untuk menangkap risiko kode yang dihasilkan AI, mengubah objek tinjauan dari kode menjadi dokumen kasus uji, membiarkan kasus uji yang gagal menggantikan manusia untuk mengawasi kesalahan dan kelembapan AI, membuat pengembangan yakin terhadap vibe coding.

Pengujian dengan bantuan AI yang diatasi bukan cakupan pengujian, melainkan masalah kepercayaan saya terhadap kode yang dihasilkan AI. AI dapat mengeluarkan sejumlah besar kode dalam tiga menit, sedangkan manusia membutuhkan dua jam untuk meninjau semuanya. Tiga menit untuk menghasilkan, dua jam untuk meninjau bukanlah hal yang berlebihan. Solusinya adalah mengganti objek tinjauan: bukan membaca kode baris demi baris, melainkan membaca dokumentasi kasus uji, lalu menggunakan pengujian unit di lingkungan pengembangan lokal untuk membangun sebuah pintu pengawal, sehingga kasus uji yang gagal dapat menggantikan saya untuk mengawasi malas dan kesalahan AI.

Bug Kecil Jadi Medan Utama Pengujian dengan Bantuan AI

Bug dibagi menjadi dua kategori: bug yang mudah diatasi, dan bug yang sulit diatasi.

Bug yang sulit diatasi biasanya berasal dari kekurangan desain arsitektur atau solusi, secara bertahap berkembang menjadi beban historis, satu perubahan mempengaruhi seluruh sistem; juga mungkin disebabkan oleh pihak ketiga, seperti perpustakaan pihak ketiga, sistem operasi, kompiler, yang memerlukan pengetahuan yang lebih spesialis dan eksplorasi mendalam untuk diatasi. Masalah kompleks ini tidak termasuk dalam cakupan pembahasan tulisan ini.

Tulisan ini fokus pada bug kecil dalam siklus hidup produk, dengan bantuan AI untuk membuat kasus uji, memecahkan masalah berikut:

  • Bug yang dapat ditemukan dengan cepat
  • Bug rendah yang hanya perlu perubahan kecil untuk diperbaiki
  • Bug baru yang diperkenalkan oleh perubahan
  • Kesalahan saat tergesa-gesa dalam perbaikan darurat
  • Perbandingan biaya dan efisiensi pengujian yang ditargetkan

Sebagian besar bug adalah bug kecil, namun bug kecil juga dapat menyebabkan masalah serius. Mengatasi bug kecil secara lokal dapat menghemat banyak tenaga di kemudian hari.

Mengganti Objek Tinjauan dari Kode Menjadi Dokumentasi Kasus Uji

Saya pernah mencoba ide yang gagah berani: membiarkan AI sepenuhnya menyelesaikan sebuah kebutuhan, tanpa meninjau kode yang dihasilkannya sama sekali, seperti dalam mode Copilot Agent yang sepenuhnya melepas tangan. Akhirnya saya menyerah. Akar masalahnya adalah tidak yakin. Untuk program biner yang logisnya ketat dan jelas 0-1, tidak yakin berarti kehilangan kepercayaan aliran atas dan bawah, kehilangan kepercayaan pelanggan. Oleh karena itu, saya mempelajari pemikiran tentang vibe coding: untuk kode yang dihasilkan AI, pasti harus yakin di hati.

Masalahnya adalah biaya tinjauan. Kadang AI menghasilkan atau memodifikasi terlalu banyak kode, tiga menit untuk menghasilkan, dua jam untuk meninjau bukanlah hal yang berlebihan. Beban kerja kode pengujian biasanya lebih banyak dari kode bisnis, dan tidak selalu dihitung dalam penilaian pengiriman pengembangan, ini adalah salah satu alasan banyak orang tidak sengaja menulis tes. Namun, fakta bahwa asisten AI lebih cerdas dari saya sudah merupakan kenyataan, alih-alih menolak, lebih baik berikan padanya sebuah pintu pengawal.

Mengganti objek tinjauan dari kode menjadi dokumentasi kasus uji adalah kunci untuk melewati simpang siul ini. Berbeda dengan kode bisnis, kasus uji yang dihasilkan AI biasanya menggambarkan skenario yang sangat spesifik, mudah untuk ditinjau dan divalidasi. Banyak kasus uji bahkan tidak perlu dibaca baris demi baris, cukup menunggu sampai terjadi kesalahan baru memeriksa secara detail. Memang berlebihan untuk mengatakan sepenuhnya tidak meninjau kode AI, namun dengan dokumentasi kasus uji yang sempurna, dapat dibuktikan tidak setiap baris kode perlu direview secara manual.

---
title: Dari Tinjauan Kode ke Tinjauan Dokumen
---
flowchart TB
    A[AI Menghasilkan Banyak Kode] e1@--> B[Biaya Tinjauan Baris Demi Baris Tinggi]
    B e2@--> C{Tinjau Apa}
    C e3@-->|Kode| D[Dua Jam Tinjauan, Tidak Yakin]
    C e4@-->|Dokumen Kasus Uji| E[Mudah Ditinjau, Validasi Cepat]
    E e5@--> F[Pintu Pengawal Pengujian Unit]
    F e6@--> G[Kasus Uji Gagal Mengekspos Masalah]

    classDef risk fill:#FFF3E0,stroke:#E65100,color:#E65100;
    classDef ok fill:#E8F5E9,stroke:#2E7D32,color:#1B5E20;
    classDef animate stroke:#EF6C00,stroke-width:2px,stroke-dasharray: 9\,5,stroke-dashoffset: 900,animation: dash 25s linear infinite;
    class D risk;
    class E,F,G ok;
    class e1,e2,e3,e4,e5,e6 animate;

Dasar Metodologi: Six Sigma dengan DMAIC

Six Sigma adalah metodologi perbaikan kualitas yang didorong data, tujuan intinya adalah dengan mengurangi variasi proses, mengontrol tingkat cacat hingga 3,4 per juta, yaitu tingkat 6σ1.

Dia memberikan alur kerja yang dapat dieksekusi DMAIC:

  • Define (Definisi): Analisis kebutuhan, mengubahnya menjadi model data, merancang struktur data dan antarmuka
  • Measure (Pengukuran): Pemantauan kasus uji, cakupan, kinerja, keamanan
  • Analyze (Analisis): Menganalisis kasus uji dan kode bisnis
  • Improve (Peningkatan): Meningkatkan kasus uji dan kode bisnis
  • Control (Kontrol): Pintu pengawal pengujian otomatis

Alat teknikon pendukung termasuk linter, pemeriksaan statis, pemeriksaan dinamis, dan kerangka pengujian. Banyak juga indikator kualitas kode yang dapat diperhatikan, seperti indikator kompleksitas (kompleksitas siklus, kompleksitas kognitif, kedalaman bersarang, keterkaitan kelas), indikator kualitas (tingkat duplikasi, panjang fungsi, angka ajaib), serta indikator pengujian (cakupan pengujian unit, tingkat lulus pengujian integrasi, validitas kasus uji, cakupan penanganan pengecualian).

Metodologi dan alat dapat membantu menemukan dan memecahkan masalah, harganya mungkin meningkatkan biaya pengiriman dan mengurangi efisiensi dalam beberapa tingkat. Dengan sumber daya terbatas, pilih metode yang dapat memberikan manfaat berkelanjutan jangka pendek, menengah, dan panjang. Pilihan saya adalah menggunakan pengujian unit sebagai alat bantu dalam proses pengembangan.

Dengan bantuan AI dalam konversi bahasa antar peran, pengembangan dapat menggabungkan keunggulan TDD, BDD, ATDD, dengan cepat menghasilkan tabel kasus uji dan kode kasus uji, meningkatkan kualitas pengiriman.

Pengujian Berdasis Tes: TDD/BDD/ATDD dengan Kode yang Dapat Diuji

Perbedaan ketiga pengujian berdasis tes adalah sebagai berikut:

DimensiTDDBDDATDD
Sumber dorongPengujian unitSkenario perilaku penggunaKondisi penerimaan
PesertaPengembangBisnis+pengembangBisnis+tes+pengembang
Tingkat tesPengujian unitPengujian integrasi/ke ujungPengujian penerimaan
Contoh alatJUnit, pytestCucumber, SpecFlowFitNesse, Robot Framework
Contoh keluaranLaporan cakupan kodeDokumen skenario pengguna yang dapat dieksekusiTingkat lulus pengujian penerimaan
Bahasaassert add(2,3) == 5Skenario bahasa alami (Given-When-Then)Bahasa bisnis (tabel kondisi penerimaan)

Kode yang dapat diuji memiliki empat prinsip inti: tanggung jawab tunggal (setiap fungsi hanya melakukan satu hal), injeksi dependensi (mengirimkan dependensi melalui parameter), isolasi antarmuka (tipe input dan output jelas), status dapat diamati (menyediakan antarmuka kueri untuk memvalidasi status internal).

Dalam prompt untuk AI, saya menyarankan langsung menulis dapat diperluas, tanggung jawab tunggal, injeksi dependensi. Saya pernah mencoba membiarkan AI mengontrol panjang fungsi dan panjang file yang dihasilkan, tingkat kepatuhannya buruk; namun setelah beralih ke tanggung jawab tunggal dan injeksi dependensi, kode yang dihasilkan jelas lebih sesuai harapan. Optimasi terlalu awal adalah akar segala kejahatan, saat menghasilkan struktur data dan antarmuka dasar, cukup beri tahu AI untuk memprioritaskan skalabilitas.

Contoh kode yang memudahkan pengujian:

// user.h
typedef struct {
    int id;
    char name[50];
    int age;
} User;

// Abstraksi antarmuka penyimpanan memori
typedef struct {
    User* (*get_user)(int id);
    int (*save_user)(const User* user);
} UserStorage;

// Membuat pengguna (injeksi dependensi antarmuka penyimpanan)
User* create_user(const char* name, int age, UserStorage* storage) {
    if(strlen(name) >= 50 || age <= 0) return NULL;

    User* new_user = malloc(sizeof(User));
    new_user->id = generate_user_id();
    strncpy(new_user->name, name, 49);
    new_user->name[49] = '\0';
    new_user->age = age;

    if(storage->save_user(new_user) != 0) {
        free(new_user);
        return NULL;
    }
    return new_user;
}

Contoh kode yang tidak memudahkan pengujian:

// Operasi database yang terikat erat
void save_user_to_db(User* user) {
    MYSQL conn;
    mysql_init(&conn);
    if(!mysql_real_connect(&conn, "localhost", "root", "pass", "test", 0, NULL, 0)) {
        log_error("DB connection failed"); // Ketergantungan log yang sulit diuji
        exit(1); // Keluar langsung mempengaruhi eksekusi pengujian
    }
    // Gabungkan SQL dan tulis ke database
}

Kode baik seperti angin yang tidak terasa, kode buruk memiliki kehadiran yang kuat. Fungsi yang mudah diuji memiliki nilai kembali yang jelas, penanganan kesalahan yang standar, parameter masukan yang jelas, isolasi efek samping, dan mendukung injeksi dependensi.

Kode yang dihasilkan AI kadang bukan praktik terbaik, gaya kodenya juga bermasalah. Meskipun seringkali dapat memecahkan masalah, proyek nyata bukan sesuatu yang selesai sekali, harus mempertimbangkan pemeliharaan di kemudian hari. Saat memberi tahu AI untuk menghasilkan kode, juga perlu menekankan prioritas keterbacaan, dapat diperluas, tanggung jawab tunggal, injeksi dependensi. Masalah gaya kode tidak akan dibahas lebih lanjut, dapat merujuk ke panduan gaya kode Google2.

Jebakan dan Perbandingan dalam Pengembangan Nyata

Kebutuhan saat disampaikan lintas peran akan melalui beberapa putaran konversi bahasa, setiap putaran dapat menghasilkan penyimpangan ungkapan. Misalnya, pelanggan mengatakan “pantau terpusat” dipahami backend sebagai “kembalian satu antarmuka” tanpa melakukan paginasi. Dengan bantuan AI untuk menghasilkan template bahasa peran, dapat mengurangi kerugian informasi dalam konversi manual.

Pemikiran yang tidak matang adalah akar banyak bug. Dengan bantuan AI merancang skenario kasus uji, ia tidak hanya dapat menyelesaikan tugas yang diharapkan, tetapi juga memberikan inspirasi di luar harapan, melengkapi detail yang tidak dipertimbangkan oleh pemberi instruksi rilis. Dalam setiap putaran konversi bahasa peran, Anda dapat berdialog dengan AI untuk memperbaiki celah. Markdown adalah bahasa yang paling mudah dipahami AI, masukan dan keluaran sebaiknya menggunakan format Markdown.

Beberapa hal yang harus diperhatikan dalam kode kasus uji: isolasi kasus uji, akurasi simulasi dependensi, validitas pernyataan, nilai batas, penanganan pengecualian, kinerja, konkuren. AI akan malas, tidak akan menghasilkan kasus uji yang mencakup semua skenario sekaligus. Menghasilkan semua kode pengujian sekaligus membutuhkan model yang tinggi, dapat dibagi menjadi beberapa kali menghasilkan.

Sebagai contoh model Claude di Cursor, ia menyelesaikan beberapa perhatian kode kasus uji dengan baik, tetapi sering lupa isolasi kasus uji dan skenario pengecualian. Menambahkan satu aturan pengguna dapat sedikit mengurangi malas: saat menghasilkan kasus uji, perhatikan dokumen kasus uji, isolasi kasus uji. Namun, ia tetap tidak akan menghasilkan semua skenario sekaligus, skenario jalur normal, jalur pengecualian, nilai batas, kinerja, konkuren, dll. perlu diisi melalui beberapa kali dialog.

Alur Kerja Pengujian dengan Bantuan AI yang Dapat Dilakukan

Dengan menggabungkan dokumen desain, dapat disatukan alur dari skenario ke kasus uji:

---
title: Alur Kerja Pengujian dengan Bantuan AI
---
flowchart TB
    A[Dokumen Desain] e1@--> B[Menghasilkan Skenario Pengujian Penerimaan]
    B e2@--> C[Menghasilkan Struktur Data dan Antarmuka]
    C e3@--> D[Menghasilkan Tabel Kasus Uji Sisi Klien]
    D e4@--> E[Menghasilkan Kode Kasus Uji]
    D e5@--> F[Menghasilkan Kode Bisnis]
    E e6@--> G[Pintu Pengawal Lokal: Kasus Uji Lulus]
    F e7@--> G
    G e8@--> H{Ada Kasus Uji Gagal}
    H e9@-->|Ya| E
    H e10@-->|Tidak| I[Kirim ke Pengujian]

    classDef input fill:#E3F2FD,stroke:#1565C0,color:#0D47A1;
    classDef gen fill:#E8F5E9,stroke:#2E7D32,color:#1B5E20;
    classDef gate fill:#FFF3E0,stroke:#E65100,color:#E65100;
    classDef animate stroke:#EF6C00,stroke-width:2px,stroke-dasharray: 9\,5,stroke-dashoffset: 900,animation: dash 25s linear infinite;
    class A input;
    class B,C,D,E,F gen;
    class G,H,I gate;
    class e1,e2,e3,e4,e5,e6,e7,e8,e9,e10 animate;

Prompt untuk setiap langkah dapat diatur sebagai berikut: menghasilkan skenario pengujian yang dapat diterima berdasarkan dokumen desain produk; menghasilkan struktur data dan antarmuka berdasarkan skenario pengujian; menghasilkan tabel kasus uji sisi klien berdasarkan skenario pengujian dan antarmuka; menghasilkan kode kasus uji berdasarkan antarmuka dan tabel kasus uji; menghasilkan kode bisnis berdasarkan skenario pengujian dan memastikan kasus uji lulus.

Ada satu ancaman di sini: AI mungkin mengubah kode bisnis berdasarkan kode pengujian, atau sebaliknya mengubah kode pengujian berdasarkan kode bisnis. Jika kedua sisi memiliki kesalahan, AI akan bingung, seiring bertambahnya percakapan, kode pengujian dan kode bisnis akan semakin acak, pada titik ini intervensi manusia diperlukan.

Contoh prompt yang terlalu ambitious adalah kontraproduktif: meminta AI untuk secara sekaligus mencakup normal, pengecualian, nilai batas, konkuren dan menghasilkan kode. Permintaan seperti ini mudah terganggu. Pendekatan yang benar adalah memecah skenario di Cursor, menggunakan beberapa permintaan untuk menghasilkan secara bertahap. Kasus uji kinerja membutuhkan banyak data, harus diletakan pada tahap pengujian sistem, pertama biarkan AI menulis generator data acak, lalu gunakan data yang dihasilkan untuk membangun kasus uji.

Pengujian integrasi membutuhkan pembangunan lingkungan pengujian. Beberapa kasus uji bergantung pada alat eksternal, misalnya isolasi mikro bergantung pada iptables dan ipset, dapat menggunakan Docker untuk membangun kontainer pengujian. Prinsipnya: bagaimana orang menguji, begitulah perintah kepada AI untuk mengimplementasikan langkah otomatisasi yang sama. Tentang pengujian keamanan, saat ini terutama bergantung pada pengalaman dan analisis, belum ada pengalaman AI yang matang untuk membantu.

Kesimpulan

Alur kerja ini dibandingkan dengan tidak menggunakan AI akan menghasilkan lebih banyak dokumen dan kode pengujian, sangat sulit untuk meninjau setiap kata. Namun dokumen lebih mudah ditinjau daripada kode, terutama tabel kasus uji, yang memiliki peran pengarahan yang akurat pada pembuatan kasus uji. Dalam pengembangan nyata, terkadang saya hanya meninjau kasus uji yang gagal, melalui debug kasus uji yang gagal untuk mengonfirmasi masalah.

Arah perbaikan ada tiga: subproses tahap desain memiliki persimpangan, skenario pengujian penerimaan mungkin bergantung pada struktur data dan antarmuka; tabel kasus uji sisi klien menjadi tanggung jawab pengembang sendiri; sebelum pengiriman perlu menghasilkan skenario pengujian terperinci yang mencakup detail kode bisnis lagi.

Manfaat akhir tidak ada pada angka cakupan pengujian, melainkan pada kepercayaan: dengan bantuan pintu pengawal pengujian unit lokal ini, saya akhirnya dapat yakin terhadap kode yang dihasilkan AI, alih-alih mengirimkan kode yang dihasilkan vibing tanpa berpikir ke produksi.


  1. Definisi Six Sigma dan metode DMAIC merujuk pada entri Wikipedia. ↩︎

  2. Google Style Guide adalah panduan gaya kode yang diterbitkan oleh Google. ↩︎