Testing dengan package:test
Menulis tes otomatis dengan package:test: test, group, expect, matcher, menguji exception dan async, setUp/tearDown, serta pola Arrange-Act-Assert.
Mengapa menguji?
Tanpa tes, setiap perubahan kode adalah pertaruhan: memperbaiki satu fitur bisa merusak yang lain tanpa kamu sadari. Tes otomatis memeriksa program dalam hitungan detik, setiap kali kamu mau. Hasilnya: berani mengubah kode, bug cepat ketahuan, dan tes menjadi dokumentasi cara pakai.
Memasang
dart pub add --dev test
dart test
Berkas tes ada di folder test/ dan namanya berakhiran _test.dart.
Tes pertamamu
Kode yang diuji (lib/kalkulator.dart):
int tambah(int a, int b) => a + b;
double bagi(int a, int b) {
if (b == 0) throw ArgumentError('Pembagi tidak boleh nol');
return a / b;
}
Tesnya (test/kalkulator_test.dart):
import 'package:test/test.dart';
import 'package:aplikasi/kalkulator.dart';
void main() {
test('tambah menjumlahkan dua angka', () {
expect(tambah(2, 3), 5);
});
test('bagi menghasilkan desimal', () {
expect(bagi(10, 4), 2.5);
});
test('bagi dengan nol melempar ArgumentError', () {
expect(() => bagi(1, 0), throwsArgumentError);
});
}
Jalankan dart test. Setiap test punya nama yang menjelaskan perilaku, dan expect(aktual, harapan) memeriksanya.
group: mengelompokkan tes
group('Kalkulator', () {
test('tambah', () => expect(tambah(1, 1), 2));
test('tambah negatif', () => expect(tambah(-1, -1), -2));
});
Matcher yang sering dipakai
| Matcher | Memeriksa |
|---|---|
equals(x) atau langsung x | Sama nilainya |
isTrue / isFalse | Boolean |
isNull / isNotNull | Null |
isA<Tipe>() | Tipe objek |
contains(x) | List/String mengandung x |
hasLength(n) | Jumlah elemen |
isEmpty / isNotEmpty | Kosong / tidak |
closeTo(x, delta) | Desimal mendekati x |
throwsA(isA<Tipe>()) | Melempar exception tertentu |
orderedEquals([...]) | List sama dan berurutan |
expect([1, 2, 3], contains(2));
expect('Dart', hasLength(4));
expect(0.1 + 0.2, closeTo(0.3, 0.0001)); // jangan bandingkan double dengan ==
expect(() => int.parse('x'), throwsFormatException);
expect(Pengguna('Budi'), isA<Pengguna>());
Menguji kode async
test('ambilNama mengembalikan Budi', () async {
expect(await ambilNama(), 'Budi');
});
test('Future berhasil', () {
expect(ambilNama(), completion('Budi'));
});
test('Future gagal', () {
expect(ambilGagal(), throwsA(isA<Exception>()));
});
test('Stream mengirim 3,2,1', () {
expect(hitungMundur(3), emitsInOrder([3, 2, 1, emitsDone]));
});
setUp dan tearDown
group('Keranjang', () {
late Keranjang keranjang;
setUp(() {
keranjang = Keranjang(); // objek baru sebelum SETIAP tes
});
test('awalnya kosong', () {
expect(keranjang.total, 0);
});
test('tambah menambah total', () {
keranjang.tambah(1000);
expect(keranjang.total, 1000);
});
});
setUp memastikan tiap tes mulai dari keadaan bersih sehingga tes tidak saling memengaruhi.
Pola Arrange – Act – Assert
| Tahap | Isi |
|---|---|
| Arrange | Siapkan objek dan data |
| Act | Jalankan satu aksi yang diuji |
| Assert | Periksa hasilnya dengan expect |
Menulis kode yang mudah diuji
- Pisahkan logika dari I/O: function murni (input → output) paling mudah dites.
- Terima dependensi lewat parameter/constructor (mis. objek
Pengirimabstrak) agar bisa diganti tiruan saat tes. - Satu tes menguji satu perilaku; beri nama yang menjelaskannya.
- Uji kasus batas: nol, kosong, negatif, nilai null, input salah.
Perintah berguna
| Perintah | Fungsi |
|---|---|
dart test | Semua tes |
dart test test/kalkulator_test.dart | Satu berkas |
dart test -n "tambah" | Tes yang namanya mengandung "tambah" |
Error umum
Expected: <5> Actual: <4>→ hasil tidak sesuai harapan; urutanexpect(aktual, harapan)jangan terbalik.Expected: throws ... Actual: <Closure>→ lupa membungkus pemanggilan dalam() => ...saat menguji exception.- Tes async selesai terlalu cepat → lupa
async/awaitatau tidak mengembalikan Future.