Program yang tidak diuji hanyalah program yang kita harapkan benar. Bagian 1 sampai 3 sesekali menjalankan satu fungsi, tetapi harapan bukan bukti. Pada bagian ini kita merangkai tiga berkas uji — unit untuk operasi, unit untuk validasi, dan end-to-end untuk program utuh — lalu menjalankannya sampai semua kasus lulus dan kegagalan apa pun terdeteksi otomatis.

Yang kita bangun pada bagian ini:

  • struktur tests/ beserta pola mengakses src/ dari berkas uji,
  • pola tabel kasus berbasis assert dan anonymous function,
  • uji kasus galat — error yang diharapkan justru harus terjadi,
  • uji end-to-end mode demo beserta pemeriksaan transkripnya,
  • checklist kualitas dan ide pengembangan lanjutan.

Struktur Berkas Uji #

Tiga berkas uji membagi tanggung jawab menurut cakupan, dari satu fungsi sampai program utuh:

BerkasCakupanKasus
uji_operasi.mfungsi operasi + validasi dimensi13
uji_validasi.mparserMatriks + seluruh aturan tolakan14
uji_end_to_end.mprogram utuh lewat mode demo4

Setiap berkas mandiri dan boleh dijalankan sendiri. Kuncinya ada di tiga baris pembuka tiap berkas:

matlab
% Pastikan folder src/ dapat diakses dari lokasi berkas ini,
% entah dijalankan dari tests/ maupun dari lokasi lain.
folderIni = fileparts(mfilename('fullpath'));
addpath(fullfile(folderIni, '..', 'src'));

Mari kita bedah baris-baris kode di atas:

  1. Baris 2 (folderIni = fileparts(mfilename('fullpath'));): mfilename('fullpath') mengembalikan lokasi berkas yang sedang berjalan — bukan folder aktif pengguna. Test menjadi tidak peduli dari mana ia dijalankan.
  2. Baris 3 (addpath(fullfile(folderIni, '..', 'src'));): fullfile merangkai path lintas sistem operasi; '..' naik satu tingkat dari tests/ ke src/. Dengan path terpasang, test bisa memanggil kalkulator dan kawan-kawannya langsung.

Pola Uji: Tabel Kasus dengan assert #

Tanpa framework, kita tetap bisa menulis test yang rapi dengan tiga bahan: tabel kasus, assert, dan try/catch. Tabel kasus sudah kita lihat pada Bagian 2 dan 3 — tiap baris memuat nama kasus dan anonymous function yang memanggil assert. Mesin pengujinya satu loop:

matlab
for k = 1:size(kasus, 1)
    try
        kasus{k, 2}();
        nLulus = nLulus + 1;
        fprintf('LULUS: %s\n', kasus{k, 1});
    catch
        nGagal = nGagal + 1;
        fprintf('GAGAL: %s\n', kasus{k, 1});
    end
end

Mari kita bedah baris-baris kode di atas:

  1. Baris 3 (kasus{k, 2}();): kurung kurawal mengambil elemen cell (sebuah function handle), lalu () mengeksekusinya. Semua kasus berjalan lewat baris yang sama — menambah kasus berarti menambah satu baris tabel, bukan menyalin loop.
  2. Baris 6 (catch): assert yang gagal melempar error; catch tanpa variabel menangkapnya dan hanya mencatat GAGAL. Satu kasus gagal tidak menghentikan kasus berikutnya — kita melihat seluruh laporan dulu.
  3. Penghitung nLulus/nGagal: di akhir berkas, ringkasan dicetak dan error() sengaja dilempar bila ada kegagalan — kode keluar proses menjadi tak-nol sehingga runner otomatis (CI, skrip) mendeteksinya tanpa membaca layar.

Menguji Kasus Galat #

Kasus galat dibalik logikanya: panggilan harus melempar error, dan pesannya harus memuat potongan teks yang diharapkan. Tabelnya punya tiga kolom — nama, panggilan, dan fragmen pesan — sementara loop pengujinya menangkap galat lalu memeriksa isinya:

matlab
for k = 1:size(galat, 1)
    lulus = false;
    try
        galat{k, 2}();   % wajib melempar galat
    catch err
        lulus = ~isempty(strfind(err.message, galat{k, 3}));
    end
    if lulus
        nLulus = nLulus + 1;
        fprintf('LULUS: %s\n', galat{k, 1});
    else
        nGagal = nGagal + 1;
        fprintf('GAGAL: %s\n', galat{k, 1});
    end
end

Pemeriksaannya bekerja bertingkat: bila panggilan tidak melempar galat, lulus tetap false (baris 2) — kasus gagal karena error yang dijanjikan tidak ada. Bila galat terjadi namun pesannya tidak memuat fragmen yang diharapkan, strfind menghasilkan kosong dan kasus juga gagal. Dengan memeriksa pesan, test melindungi kontrak yang paling terlihat pengguna: teks galat yang informatif dari Bagian 3 tidak boleh berubah tanpa disadari.

Uji End-to-End Mode Demo #

Uji unit membuktikan tiap fungsi benar; uji end-to-end membuktikan rakitannya berjalan. Di sinilah mode demo dari Bagian 1 terbayar: kalkulator('demo') menjalankan delapan skenario tanpa keyboard, sehingga bisa dieksekusi dari test. evalc menangkap seluruh keluarannya sebagai teks:

matlab
% ---- kasus 1: seluruh skenario demo berjalan tanpa galat ----
% evalc menjalankan kalkulator('demo') dan menangkap seluruh
% keluarannya sebagai teks, sehingga program tetap diuji penuh
% tanpa mencetak puluhan baris sesi ke layar.
transkrip = '';
ok1 = false;
try
    transkrip = evalc('kalkulator(''demo'');');
    ok1 = true;
catch err
    fprintf('  mode demo melempar galat: %s\n', err.message);
end

Berkas ini juga menguji hasil antara — matriks dari teks skenario diperiksa hasil tambah dan kalinya — lalu memeriksa transkrip memuat hasil kunci tiap skenario:

matlab
ok4 = ~isempty(strfind(transkrip, 'Hasil:')) && ...
    ~isempty(strfind(transkrip, 'Determinan = 10')) && ...
    ~isempty(strfind(transkrip, 'Ukuran tidak kompatibel: 2x2 vs 3x2')) && ...
    ~isempty(strfind(transkrip, 'Pilihan tidak dikenal')) && ...
    ~isempty(strfind(transkrip, 'Terima kasih. Program selesai.'));

Lima fragmen itu sengaja dipilih: Hasil: membuktikan operasi mencetak hasil, Determinan = 10 membuktikan hitungan skenario kelima benar, Ukuran tidak kompatibel: 2x2 vs 3x2 membuktikan galat dimensi tertangkap (program tidak berhenti), Pilihan tidak dikenal membuktikan cabang otherwise hidup, dan Terima kasih. Program selesai. membuktikan loop berakhir dengan rapi. Menjalankan berkas dari folder tests/ memberi hasil:

Output yang Dihasilkan:

text
== uji_end_to_end.m ==
Matriks A (contoh: 1 2; 3 4): 1 2; 3 4
LULUS: mode demo berjalan penuh tanpa galat
LULUS: bacaMatriks mode demo mengembalikan matriks
LULUS: hasil antara konsisten dengan data skenario
LULUS: transkrip memuat hasil kunci tiap skenario

Ringkasan: 4 lulus, 0 gagal (total 4)

Baris kedua adalah gema bacaMatriks mode demo — bukan kebocoran, melainkan bukti jalur baca ikut teruji. Peta cakupan ketiga berkas tersusun berlapis:

Hasil Uji Menyeluruh #

Ketiga berkas dijalankan utuh lewat runner Octave 10.3 dalam mode batch. Ringkasan akhirnya:

BerkasCakupanKasusHasil
uji_operasi.moperasi + validasi dimensi1313 lulus, 0 gagal
uji_validasi.mparser + aturan tolakan1414 lulus, 0 gagal
uji_end_to_end.mprogram utuh mode demo44 lulus, 0 gagal

Total 31 kasus, semuanya lulus, dan ketiganya berakhir dengan kode keluar 0 karena berkas uji memang dilempar error hanya bila ada kegagalan. Dari 31 kasus itu, 12 di antaranya adalah kasus galat — program diuji justru pada kondisi ketika semuanya salah.

Checklist Kualitas Program #

Sebelum menutup proyek, mari audit hasil kerja kita terhadap janji-janji di Bagian 1:

Aspek kualitasBukti
Input pengguna tidak dieksekusiparser tanpa eval/str2num; kasus token terlarang lulus
Dimensi diperiksa sebelum menghitungvalidasiDimensi dipanggil semua operasi biner; 3 kasus galat dimensi
Determinan hanya untuk matriks persegivalidasiPersegi; kasus determinan 2x3 ditolak
Program tahan galatskenario demo ke-6: galat tercetak, menu kembali
Pilihan tak dikenal tidak menghentikan programskenario 9 jatuh ke otherwise
Ukuran dibatasi 10x10kasus 11 baris dan 11 kolom ditolak
Nilai meluap ditolakkasus 1e999 ditolak dengan pesan rentang
Keluaran rapi dan deterministiktampilkanMatriks rata kanan; format %g tuntas

Delapan dari delapan — checklist terpenuhi karena setiap barisnya punya kasus uji yang menyandang bukti, bukan keyakinan.

Ide Pengembangan Lanjutan #

Struktur yang ada — menu, dispatch, parser, dan test — siap menampung fitur baru. Kandidat berikut urut dari yang paling mudah:

  • invers matriks — cabang menu baru inversMatriks.m; validasi: matriks persegi dan det(A) ~= 0,
  • trace, rank, dan nilai eigen — semua satu validasiPersegi plus satu panggilan bawaan trace, rank, atau eig,
  • matriks siap pakai — perintah identitas n dan nol m n yang mengisi matriks lewat eye/zeros,
  • riwayat hasil — simpan hasil terakhir, lalu teks hasil pada prompt dipakai sebagai matriks baru,
  • presisi tampilan — opsi menu untuk mengganti %g menjadi %.3f,
  • baca dari file — bacaMatriks menambang jalur: dari fopen+fgetl per baris, hasilnya tetap melewati parserMatriks.

Setiap kandidat menuntut hal yang sama: satu fungsi baru di src/, satu cabang switch di kalkulator.m, satu baris skenario demo, dan beberapa baris kasus uji — pola kerja yang sudah terbukti.

Proyek kalkulator matriks tuntas: kerangka dari Bagian 1, mesin hitung dari Bagian 2, gerbang validasi dari Bagian 3, dan bukti dari Bagian 4 membentuk satu program interaktif yang tahan salah ketik dan teruji menyeluruh. Pola yang kita pakai — loop menu, dispatch switch, parser tanpa eval, validasi fail-fast, dan uji berlapis — adalah cetak biru yang bisa kamu bawa ke program MATLAB berikutnya, sekecil apa pun mulainya.