Unit Test #
Unit testing adalah proses pengujian bagian-bagian kecil dari kode (disebut unit) secara terpisah untuk memastikan bahwa mereka bekerja sebagaimana mestinya. Dalam bahasa Dart, unit testing adalah praktik yang penting untuk memastikan bahwa aplikasi atau pustaka yang Anda kembangkan bekerja dengan benar.
Dart menyediakan dukungan bawaan untuk unit testing melalui pustaka test
. Pustaka ini memungkinkan Anda untuk menulis, menjalankan, dan mengelola unit test dengan mudah. Pada artikel ini, kita akan membahas berbagai aspek dari unit testing dalam Dart, mulai dari instalasi, penulisan test, hingga praktik terbaik.
Mengapa Unit Testing Penting? #
Unit testing membantu dalam:
- Mendeteksi Bug Sejak Dini: Menemukan dan memperbaiki bug pada tahap awal pengembangan.
- Memastikan Kode Tetap Stabil: Membantu memastikan bahwa perubahan kode tidak menyebabkan kerusakan pada fungsionalitas yang sudah ada.
- Mendukung Refactoring: Memungkinkan Anda melakukan refactoring kode dengan percaya diri, karena unit test akan memberitahu Anda jika ada sesuatu yang rusak.
- Dokumentasi: Unit test bisa berfungsi sebagai dokumentasi yang menjelaskan bagaimana kode seharusnya bekerja.
Instalasi Pustaka test
#
Sebelum mulai menulis unit test, Anda harus menginstal pustaka test
. Caranya adalah dengan menambahkan test
ke dalam file pubspec.yaml
Anda.
dev_dependencies:
test: ^1.22.0
Setelah menambahkan pustaka ini, jalankan perintah berikut di terminal untuk menginstalnya:
pub get
Membuat dan Menjalankan Unit Test #
Unit test dalam Dart biasanya ditulis dalam file yang terpisah, dengan konvensi penamaan menggunakan akhiran _test.dart
. Misalnya, jika Anda memiliki file calculator.dart
, Anda bisa membuat file calculator_test.dart
untuk menulis unit test.
Contoh Sederhana #
Mari kita mulai dengan contoh sederhana di mana kita akan menulis unit test untuk fungsi penjumlahan.
File: lib/calculator.dart
class Calculator {
int add(int a, int b) {
return a + b;
}
}
File: test/calculator_test.dart
import 'package:test/test.dart';
import '../lib/calculator.dart';
void main() {
group('Calculator', () {
test('penjumlahan dua angka', () {
final calculator = Calculator();
expect(calculator.add(2, 3), 5);
});
});
}
Penjelasan:
- group:
group
digunakan untuk mengelompokkan beberapa test yang terkait. Dalam contoh ini, kita mengelompokkan semua test yang berkaitan denganCalculator
. - test:
test
mendefinisikan satu unit test. Fungsi ini memerlukan dua argumen: deskripsi test dan fungsi yang berisi logika test. - expect:
expect
digunakan untuk membandingkan hasil aktual dengan hasil yang diharapkan.
Menjalankan Unit Test #
Untuk menjalankan unit test, Anda bisa menggunakan perintah berikut di terminal:
dart test
Perintah ini akan mencari semua file dengan akhiran _test.dart
di dalam direktori test
dan menjalankan test di dalamnya.
Assertions dalam Dart #
Assertions digunakan dalam unit test untuk memverifikasi apakah kondisi tertentu terpenuhi. Fungsi expect
dalam Dart mendukung berbagai jenis assertions, seperti:
-
Equality Assertion:
expect(actual, expected);
Memastikan bahwa nilai aktual sama dengan nilai yang diharapkan.
-
Throws Assertion:
expect(() => someFunction(), throwsException);
Memastikan bahwa fungsi tertentu melemparkan sebuah pengecualian.
-
Type Assertion:
expect(someObject, isA<SomeType>());
Memastikan bahwa objek adalah instance dari tipe tertentu.
-
Contains Assertion:
expect(list, contains(element));
Memastikan bahwa suatu list berisi elemen tertentu.
Test Setup dan Teardown #
Dalam beberapa kasus, Anda mungkin perlu melakukan setup atau inisialisasi sebelum menjalankan test, atau membersihkan sumber daya setelah test selesai. Untuk ini, Dart menyediakan fungsi setUp
dan tearDown
.
Contoh:
import 'package:test/test.dart';
void main() {
setUp(() {
// Inisialisasi sebelum setiap test dijalankan
print('Inisialisasi sebelum test');
});
tearDown(() {
// Pembersihan setelah setiap test selesai
print('Pembersihan setelah test');
});
test('contoh test', () {
expect(2 + 2, 4);
});
}
- setUp: Dipanggil sebelum setiap test dalam satu group dijalankan.
- tearDown: Dipanggil setelah setiap test selesai dijalankan.
Test Asinkron #
Dart mendukung test asinkron menggunakan async
dan await
. Ini berguna ketika Anda perlu menguji kode yang melibatkan operasi asinkron seperti pemanggilan API atau operasi I/O.
Contoh:
import 'package:test/test.dart';
Future<String> fetchData() async {
return Future.delayed(Duration(seconds: 1), () => 'data diterima');
}
void main() {
test('pengujian fetchData', () async {
var data = await fetchData();
expect(data, 'data diterima');
});
}
Penjelasan:
-
await: Digunakan untuk menunggu hasil dari operasi asinkron.
-
async: Menandakan bahwa fungsi tersebut akan menjalankan operasi asinkron.
Mocking dalam Unit Test #
Mocking adalah teknik untuk mensimulasikan objek atau fungsionalitas dalam test, sehingga Anda bisa menguji bagian kode tertentu secara terisolasi. Dart menyediakan paket mockito
untuk melakukan mocking.
Instalasi Paket Mockito:
Tambahkan dependensi mockito
di pubspec.yaml
:
dev_dependencies:
mockito: ^5.0.0
build_runner: ^2.1.0
Contoh Mocking:
Misalkan kita memiliki kelas Database
yang berinteraksi dengan database dan kita ingin menguji UserService
yang bergantung pada Database
.
File: lib/database.dart
class Database {
Future<String> getUserData(int userId) async {
// Interaksi dengan database
return 'User Data';
}
}
File: lib/user_service.dart
import 'database.dart';
class UserService {
final Database database;
UserService(this.database);
Future<String> getUserName(int userId) async {
return await database.getUserData(userId);
}
}
File: test/user_service_test.dart
import 'package:test/test.dart';
import 'package:mockito/mockito.dart';
import '../lib/database.dart';
import '../lib/user_service.dart';
// Membuat mock dari Database
class MockDatabase extends Mock implements Database {}
void main() {
group('UserService', () {
MockDatabase mockDatabase;
UserService userService;
setUp(() {
mockDatabase = MockDatabase();
userService = UserService(mockDatabase);
});
test('getUserName memanggil getUserData di Database', () async {
// Mengatur respons yang diharapkan dari mock
when(mockDatabase.getUserData(1)).thenAnswer((_) async => 'Mocked User Data');
// Memanggil method yang akan diuji
var result = await userService.getUserName(1);
// Memverifikasi hasilnya
expect(result, 'Mocked User Data');
// Memverifikasi bahwa method getUserData dipanggil sekali
verify(mockDatabase.getUserData(1)).called(1);
});
});
}
Penjelasan:
- MockDatabase: Kelas ini adalah mock dari
Database
yang kita buat menggunakanmockito
. - when: Digunakan untuk mendefinisikan perilaku dari method yang dimock ketika dipanggil dalam test.
- verify: Memverifikasi bahwa method tertentu dipanggil selama eksekusi test.
Coverage Testing #
Coverage testing adalah teknik untuk mengukur seberapa besar bagian kode yang diuji oleh unit test. Dart mendukung coverage testing melalui paket coverage
.
Instalasi Paket:
Tambahkan coverage
di pubspec.yaml
:
dev_dependencies:
coverage: ^1.0.0
Menjalankan Coverage Testing:
Untuk menjalankan coverage testing, gunakan perintah berikut:
dart run test --coverage coverage
Hasilnya akan disimpan dalam direktori coverage
. Anda dapat menggunakan alat pihak ketiga seperti lcov
untuk menghasilkan laporan HTML yang lebih mudah dibaca.
Praktik Terbaik #
- Isolasi Unit Test: Pastikan setiap unit test diisolasi dari yang lain, sehingga hasil satu test tidak memengaruhi hasil test lain.
- **
Tes dengan Skenario Positif dan Negatif**: Uji kode Anda dengan input yang valid dan tidak valid untuk memastikan bahwa kode menangani semua skenario dengan benar.
- Gunakan Mocking dengan Bijak: Gunakan mocking untuk mengisolasi unit kode yang ingin diuji, tetapi jangan terlalu sering menggunakan mocking sehingga tes Anda kehilangan keterkaitan dengan dunia nyata.
- Perbarui Unit Test Secara Berkala: Pastikan bahwa unit test diperbarui setiap kali ada perubahan signifikan pada kode.
Kesimpulan #
Unit testing dalam bahasa Dart adalah komponen penting dalam pengembangan aplikasi yang andal dan berkualitas tinggi. Dengan menggunakan pustaka test
, Anda dapat dengan mudah menulis, menjalankan, dan mengelola unit test. Pemahaman tentang berbagai jenis assertions, setup dan teardown, tes asinkron, serta mocking adalah kunci untuk menulis unit test yang efektif dan efisien.
Dengan mengikuti praktik terbaik dalam unit testing, Anda dapat memastikan bahwa aplikasi Dart Anda tetap stabil, mudah dirawat, dan bebas dari bug, sekaligus mendokumentasikan cara kerja kode Anda.