Pengujian Unit
Tip
Konten ini adalah kutipan dari eBook, Pola Aplikasi Perusahaan Menggunakan .NET MAUI, tersedia di .NET Docs atau sebagai PDF gratis yang dapat diunduh yang dapat dibaca secara offline.
Aplikasi multi-platform mengalami masalah yang mirip dengan aplikasi desktop dan berbasis web. Pengguna seluler akan berbeda dengan perangkat mereka, konektivitas jaringan, ketersediaan layanan, dan berbagai faktor lainnya. Oleh karena itu, aplikasi multi-platform harus diuji karena akan digunakan di dunia nyata untuk meningkatkan kualitas, keandalan, dan performa mereka. Banyak jenis pengujian harus dilakukan pada aplikasi, termasuk pengujian unit, pengujian integrasi, dan pengujian antarmuka pengguna. Pengujian unit adalah bentuk yang paling umum dan penting untuk membangun aplikasi berkualitas tinggi.
Pengujian unit mengambil unit kecil aplikasi, biasanya metode, mengisolasinya dari sisa kode, dan memverifikasi bahwa itu bersifat seperti yang diharapkan. Tujuannya adalah untuk memeriksa bahwa setiap unit fungsionalitas berfungsi seperti yang diharapkan, sehingga kesalahan tidak menyebar ke seluruh aplikasi. Mendeteksi bug di mana itu terjadi lebih efisien daripada mengamati efek bug secara tidak langsung pada titik kegagalan sekunder.
Pengujian unit memiliki efek paling signifikan pada kualitas kode ketika merupakan bagian integral dari alur kerja pengembangan perangkat lunak. Pengujian unit dapat bertindak sebagai dokumentasi desain dan spesifikasi fungsi untuk aplikasi. Segera setelah metode ditulis, pengujian unit harus ditulis yang memverifikasi perilaku metode sebagai respons terhadap kasus data standar, batas, dan input yang salah dan memeriksa asumsi eksplisit atau implisit yang dibuat oleh kode. Atau, dengan pengembangan berbasis pengujian, pengujian unit ditulis sebelum kode. Untuk informasi selengkapnya tentang pengembangan berbasis pengujian dan cara menerapkannya, lihat Walkthrough: Pengembangan berbasis pengujian menggunakan Test Explorer..
Catatan
Pengujian unit sangat efektif terhadap regresi. Artinya, fungsionalitas yang digunakan untuk bekerja, tetapi telah terganggu oleh pembaruan yang rusak.
Pengujian unit biasanya menggunakan pola arrange-act-assert:
Langkah | Deskripsi |
---|---|
Atur | Menginisialisasi objek dan mengatur nilai data yang diteruskan ke metode di bawah pengujian. |
Bertindak | Memanggil metode di bawah pengujian dengan argumen yang diperlukan. |
Assert | Memverifikasi bahwa tindakan metode yang sedang diuji berulah seperti yang diharapkan. |
Pola ini memastikan bahwa pengujian unit dapat dibaca, digambarkan sendiri, dan konsisten.
Injeksi dependensi dan pengujian unit
Salah satu motivasi untuk mengadopsi arsitektur yang digabungkan secara longgar adalah memfasilitasi pengujian unit. Salah satu jenis yang terdaftar dengan layanan injeksi dependensi adalah IAppEnvironmentService
antarmuka. Contoh kode berikut menunjukkan kerangka kelas ini:
public class OrderDetailViewModel : ViewModelBase
{
private IAppEnvironmentService _appEnvironmentService;
public OrderDetailViewModel(
IAppEnvironmentService appEnvironmentService,
IDialogService dialogService, INavigationService navigationService, ISettingsService settingsService)
: base(dialogService, navigationService, settingsService)
{
_appEnvironmentService = appEnvironmentService;
}
}
Kelas OrderDetailViewModel
memiliki dependensi pada IAppEnvironmentService
jenis, yang diselesaikan kontainer injeksi dependensi saat membuat instans OrderDetailViewModel
objek. Namun, daripada membuat IAppEnvironmentService
objek yang menggunakan server, perangkat, dan konfigurasi nyata untuk menguji OrderDetailViewModel
kelas secara unit, sebagai gantinya, ganti IAppEnvironmentService
objek dengan objek tiruan untuk tujuan pengujian. Objek tiruan adalah objek yang memiliki tanda tangan objek atau antarmuka yang sama, tetapi dibuat dengan cara tertentu untuk membantu pengujian unit. Ini sering digunakan dengan injeksi dependensi untuk menyediakan implementasi antarmuka tertentu untuk menguji skenario data dan alur kerja yang berbeda.
Pendekatan ini memungkinkan IAppEnvironmentService
objek untuk diteruskan ke OrderDetailViewModel
kelas pada runtime, dan demi kepentingan uji coba, memungkinkan kelas tiruan untuk diteruskan ke kelas pada OrderDetailViewModel
waktu pengujian. Keuntungan utama dari pendekatan ini adalah memungkinkan pengujian unit dijalankan tanpa memerlukan sumber daya yang berat seperti fitur platform runtime, layanan web, atau database.
Menguji aplikasi MVVM
Menguji model dan melihat model dari aplikasi MVVM identik dengan menguji kelas lain, dan menggunakan alat dan teknik yang sama; ini termasuk fitur seperti pengujian unit dan tiruan. Namun, beberapa pola yang khas untuk memodelkan dan melihat kelas model dapat memperoleh manfaat dari teknik pengujian unit tertentu.
Tip
Uji satu hal dengan setiap pengujian unit. Ketika kompleksitas pengujian meluas, itu membuat verifikasi pengujian itu lebih sulit. Dengan membatasi pengujian unit untuk satu kekhawatiran, kami dapat memastikan bahwa pengujian kami lebih berulang, terisolasi, dan memiliki waktu eksekusi yang lebih kecil. Lihat Praktik terbaik pengujian unit dengan .NET untuk praktik terbaik lainnya.
Jangan tergoda untuk membuat latihan pengujian unit lebih dari satu aspek perilaku unit. Melakukannya mengarah pada pengujian yang sulit dibaca dan diperbarui. Ini juga dapat menyebabkan kebingungan saat menafsirkan kegagalan.
Aplikasi multi-platform eShop menggunakan MSTest untuk melakukan pengujian unit, yang mendukung dua jenis pengujian unit yang berbeda:
Jenis Pengujian | Atribut | Deskripsi |
---|---|---|
TestMethod | TestMethod |
Menentukan metode pengujian aktual yang akan dijalankan. |
DataSource | DataSource |
Pengujian yang hanya berlaku untuk sekumpulan data tertentu. |
Pengujian unit yang disertakan dengan aplikasi multi-platform eShop adalah TestMethod, sehingga setiap metode pengujian unit dihiasi dengan TestMethod
atribut . Selain MSTest ada beberapa kerangka kerja pengujian lain yang tersedia termasuk NUnit dan xUnit.
Menguji fungsionalitas asinkron
Saat menerapkan pola MVVM, lihat model biasanya memanggil operasi pada layanan, seringkali secara asinkron. Pengujian untuk kode yang memanggil operasi ini biasanya menggunakan tiruan sebagai pengganti layanan aktual. Contoh kode berikut menunjukkan pengujian fungsionalitas asinkron dengan meneruskan layanan tiruan ke dalam model tampilan:
[TestMethod]
public async Task OrderPropertyIsNotNullAfterViewModelInitializationTest()
{
// Arrange
var orderService = new OrderMockService();
var orderViewModel = new OrderDetailViewModel(orderService);
// Act
var order = await orderService.GetOrderAsync(1, GlobalSetting.Instance.AuthToken);
await orderViewModel.InitializeAsync(order);
// Assert
Assert.IsNotNull(orderViewModel.Order);
}
Pengujian unit ini memeriksa bahwa Order
properti OrderDetailViewModel
instans akan memiliki nilai setelah InitializeAsync
metode dipanggil. Metode InitializeAsync
ini dipanggil saat tampilan terkait model tampilan dinavigasi. Untuk informasi selengkapnya tentang navigasi, lihat Navigasi.
OrderDetailViewModel
Saat instans dibuat, instans IOrderService
akan ditentukan sebagai argumen. Namun, mengambil OrderService
data dari layanan web. Oleh karena itu, OrderMockService
instans, versi tiruan kelas OrderService
, ditentukan sebagai argumen ke OrderDetailViewModel
konstruktor. Kemudian, data tiruan diambil daripada berkomunikasi dengan layanan web ketika metode model InitializeAsync
tampilan dipanggil, yang menggunakan IOrderService
operasi.
Menguji implementasi INotifyPropertyChanged
INotifyPropertyChanged
Menerapkan antarmuka memungkinkan tampilan bereaksi terhadap perubahan yang berasal dari model tampilan dan model. Perubahan ini tidak terbatas pada data yang ditampilkan dalam kontrol -- perubahan tersebut juga digunakan untuk mengontrol tampilan, seperti melihat status model yang menyebabkan animasi dimulai atau kontrol dinonaktifkan.
Properti yang dapat diperbarui langsung oleh pengujian unit dapat diuji dengan melampirkan penanganan aktivitas ke PropertyChanged
peristiwa dan memeriksa apakah peristiwa dinaikkan setelah menetapkan nilai baru untuk properti. Contoh kode berikut menunjukkan pengujian seperti itu:
[TestMethod]
public async Task SettingOrderPropertyShouldRaisePropertyChanged()
{
var invoked = false;
var orderService = new OrderMockService();
var orderViewModel = new OrderDetailViewModel(orderService);
orderViewModel.PropertyChanged += (sender, e) =>
{
if (e.PropertyName.Equals("Order"))
invoked = true;
};
var order = await orderService.GetOrderAsync(1, GlobalSetting.Instance.AuthToken);
await orderViewModel.InitializeAsync(order);
Assert.IsTrue(invoked);
}
Pengujian unit ini memanggil InitializeAsync
metode OrderViewModel
kelas, yang menyebabkan propertinya Order
diperbarui. Pengujian unit akan lulus, asalkan PropertyChanged
peristiwa dinaikkan untuk Order
properti.
Menguji komunikasi berbasis pesan
Lihat model yang menggunakan MessagingCenter
kelas untuk berkomunikasi antara kelas yang digabungkan secara longgar dapat diuji unit dengan berlangganan pesan yang dikirim oleh kode di bawah pengujian, seperti yang ditunjukkan dalam contoh kode berikut:
[TestMethod]
public void AddCatalogItemCommandSendsAddProductMessageTest()
{
var messageReceived = false;
var catalogService = new CatalogMockService();
var catalogViewModel = new CatalogViewModel(catalogService);
MessagingCenter.Subscribe<CatalogViewModel, CatalogItem>(
this, MessageKeys.AddProduct, (sender, arg) =>
{
messageReceived = true;
});
catalogViewModel.AddCatalogItemCommand.Execute(null);
Assert.IsTrue(messageReceived);
}
Pengujian unit ini memeriksa bahwa CatalogViewModel
menerbitkan AddProduct
pesan sebagai respons terhadap pesan AddCatalogItemCommand
yang dijalankan.
MessagingCenter
Karena kelas mendukung langganan pesan multicast, pengujian unit dapat berlangganan AddProduct
pesan dan menjalankan delegasi panggilan balik sebagai respons untuk menerimanya. Delegasi panggilan balik ini, yang ditentukan sebagai ekspresi lambda, menetapkan bidang boolean yang digunakan oleh Assert
pernyataan untuk memverifikasi perilaku pengujian.
Menguji penanganan pengecualian
Pengujian unit juga dapat ditulis bahwa periksa apakah pengecualian tertentu dilemparkan untuk tindakan atau input yang tidak valid, seperti yang ditunjukkan dalam contoh kode berikut:
[TestMethod]
public void InvalidEventNameShouldThrowArgumentExceptionText()
{
var behavior = new MockEventToCommandBehavior
{
EventName = "OnItemTapped"
};
var listView = new ListView();
Assert.Throws<ArgumentException>(() => listView.Behaviors.Add(behavior));
}
Pengujian unit ini akan melemparkan pengecualian karena ListView
kontrol tidak memiliki peristiwa bernama OnItemTapped
. Metode Assert.Throws<T>
ini adalah metode generik di mana T
adalah jenis pengecualian yang diharapkan. Argumen yang diteruskan ke Assert.Throws<T>
metode adalah ekspresi lambda yang akan melemparkan pengecualian. Oleh karena itu, pengujian unit akan lulus asalkan ekspresi lambda melempar ArgumentException
.
Tip
Hindari menulis pengujian unit yang memeriksa string pesan pengecualian. String pesan pengecualian mungkin berubah dari waktu ke waktu, sehingga pengujian unit yang mengandalkan kehadirannya dianggap rapuh.
Validasi pengujian
Ada dua aspek untuk menguji implementasi validasi: menguji bahwa aturan validasi apa pun diimplementasikan dengan benar dan pengujian yang dilakukan kelas seperti yang ValidatableObject<T>
diharapkan.
Logika validasi biasanya mudah diuji, karena biasanya merupakan proses mandiri di mana output tergantung pada input. Harus ada pengujian pada hasil pemanggilan Validate
metode pada setiap properti yang memiliki setidaknya satu aturan validasi terkait, seperti yang ditunjukkan dalam contoh kode berikut:
[TestMethod]
public void CheckValidationPassesWhenBothPropertiesHaveDataTest()
{
var mockViewModel = new MockViewModel();
mockViewModel.Forename.Value = "John";
mockViewModel.Surname.Value = "Smith";
var isValid = mockViewModel.Validate();
Assert.IsTrue(isValid);
}
Pengujian unit ini memeriksa bahwa validasi berhasil ketika dua ValidatableObject<T>
properti dalam MockViewModel
instans keduanya memiliki data.
Selain memeriksa bahwa validasi berhasil, pengujian unit validasi juga harus memeriksa nilai Value
properti , , IsValid
dan Errors
dari setiap ValidatableObject<T>
instans, untuk memverifikasi bahwa kelas berfungsi seperti yang diharapkan. Contoh kode berikut menunjukkan pengujian unit yang melakukan ini:
[TestMethod]
public void CheckValidationFailsWhenOnlyForenameHasDataTest()
{
var mockViewModel = new MockViewModel();
mockViewModel.Forename.Value = "John";
bool isValid = mockViewModel.Validate();
Assert.IsFalse(isValid);
Assert.IsNotNull(mockViewModel.Forename.Value);
Assert.IsNull(mockViewModel.Surname.Value);
Assert.IsTrue(mockViewModel.Forename.IsValid);
Assert.IsFalse(mockViewModel.Surname.IsValid);
Assert.AreEqual(mockViewModel.Forename.Errors.Count(), 0);
Assert.AreNotEqual(mockViewModel.Surname.Errors.Count(), 0);
}
Pengujian unit ini memeriksa bahwa validasi gagal ketika Surname
properti MockViewModel
tidak memiliki data apa pun, dan Value
properti , , IsValid
dan Errors
dari setiap ValidatableObject<T>
instans diatur dengan benar.
Ringkasan
Pengujian unit mengambil unit kecil aplikasi, biasanya metode, mengisolasinya dari sisa kode, dan memverifikasi bahwa itu bersifat seperti yang diharapkan. Tujuannya adalah untuk memeriksa bahwa setiap unit fungsionalitas berfungsi seperti yang diharapkan, sehingga kesalahan tidak menyebar ke seluruh aplikasi.
Perilaku objek yang sedang diuji dapat diisolasi dengan mengganti objek dependen dengan objek tiruan yang mensimulasikan perilaku objek dependen. Ini memungkinkan pengujian unit dijalankan tanpa memerlukan sumber daya yang tidak berat seperti fitur platform runtime, layanan web, atau database
Menguji model dan melihat model dari aplikasi MVVM identik dengan menguji kelas lain, dan alat dan teknik yang sama dapat digunakan.