Razor Pengujian unit halaman di ASP.NET Core
ASP.NET Core mendukung pengujian Razor unit aplikasi Pages. Pengujian lapisan akses data (DAL) dan model halaman membantu memastikan:
- Bagian dari Razor aplikasi Pages bekerja secara independen dan bersama-sama sebagai unit selama konstruksi aplikasi.
- Kelas dan metode memiliki cakupan tanggung jawab yang terbatas.
- Dokumentasi tambahan ada tentang bagaimana aplikasi harus berakibat.
- Regresi, yang merupakan kesalahan yang dibawa oleh pembaruan pada kode, ditemukan selama pembuatan dan penyebaran otomatis.
Topik ini mengasumsikan bahwa Anda memiliki pemahaman Razor dasar tentang aplikasi Pages dan pengujian unit. Jika Anda tidak terbiasa dengan Razor aplikasi Pages atau konsep pengujian, lihat topik berikut:
- Pengantar Razor Halaman di ASP.NET Core
- Tutorial: Mulai menggunakan Razor Pages di ASP.NET Core
- Pengujian unit C# di .NET Core menggunakan uji dotnet dan xUnit
Melihat atau mengunduh kode sampel (cara mengunduh)
Proyek sampel terdiri dari dua aplikasi:
App | Folder proyek | Deskripsi |
---|---|---|
Aplikasi pesan | src/RazorPagesTestSample | Memungkinkan pengguna menambahkan pesan, menghapus satu pesan, menghapus semua pesan, dan menganalisis pesan (menemukan jumlah rata-rata kata per pesan). |
Menguji aplikasi | tests/RazorPagesTestSample.Tests | Digunakan untuk menguji unit model halaman DAL dan Indeks aplikasi pesan. |
Pengujian dapat dijalankan menggunakan fitur pengujian bawaan IDE, seperti Visual Studio. Jika menggunakan Visual Studio Code atau baris perintah, jalankan perintah berikut pada prompt perintah di folder tests/RazorPagesTestSample.Tests :
dotnet test
Organisasi aplikasi pesan
Aplikasi pesan adalah Razor sistem pesan Pages dengan karakteristik berikut:
- Halaman Indeks aplikasi (
Pages/Index.cshtml
danPages/Index.cshtml.cs
) menyediakan metode UI dan model halaman untuk mengontrol penambahan, penghapusan, dan analisis pesan (temukan jumlah rata-rata kata per pesan). - Pesan dijelaskan oleh
Message
kelas (Data/Message.cs
) dengan dua properti:Id
(kunci) danText
(pesan). PropertiText
diperlukan dan dibatasi hingga 200 karakter. - Pesan disimpan menggunakan database dalam memori Entity Framework†.
- Aplikasi ini berisi DAL di kelas konteks databasenya,
AppDbContext
(Data/AppDbContext.cs
). Metode DAL ditandaivirtual
, yang memungkinkan mocking metode untuk digunakan dalam pengujian. - Jika database kosong pada startup aplikasi, penyimpanan pesan diinisialisasi dengan tiga pesan. Pesan benih ini juga digunakan dalam pengujian.
† Topik EF, Uji dengan InMemory, menjelaskan cara menggunakan database dalam memori untuk pengujian dengan MSTest. Topik ini menggunakan kerangka kerja pengujian xUnit . Konsep pengujian dan implementasi pengujian di berbagai kerangka kerja pengujian serupa tetapi tidak identik.
Meskipun aplikasi sampel tidak menggunakan pola repositori dan bukan contoh pola Unit kerja (UoW) yang efektif, Razor Pages mendukung pola pengembangan ini. Untuk informasi selengkapnya, lihat Merancang lapisan persistensi infrastruktur dan Logika pengontrol Pengujian di ASP.NET Core (sampel mengimplementasikan pola repositori).
Menguji organisasi aplikasi
Aplikasi pengujian adalah aplikasi konsol di dalam folder tests/RazorPagesTestSample.Tests .
Menguji folder aplikasi | Deskripsi |
---|---|
UnitTests |
|
Utilitas | Berisi metode yang TestDbContextOptions digunakan untuk membuat opsi konteks database baru untuk setiap pengujian unit DAL sehingga database diatur ulang ke kondisi garis besarnya untuk setiap pengujian. |
Kerangka kerja pengujian adalah xUnit. Kerangka kerja tiruan objek adalah Moq.
Pengujian unit lapisan akses data (DAL)
Aplikasi pesan memiliki DAL dengan empat metode yang terkandung dalam AppDbContext
kelas (src/RazorPagesTestSample/Data/AppDbContext.cs
). Setiap metode memiliki satu atau dua pengujian unit di aplikasi pengujian.
Metode DAL | Fungsi |
---|---|
GetMessagesAsync |
Mendapatkan dari database yang List<Message> diurutkan menurut Text properti . |
AddMessageAsync |
Message Menambahkan ke database. |
DeleteAllMessagesAsync |
Menghapus semua Message entri dari database. |
DeleteMessageAsync |
Menghapus satu Message dari database dengan Id . |
Pengujian unit DAL diperlukan DbContextOptions saat membuat baru AppDbContext
untuk setiap pengujian. Salah satu pendekatan untuk membuat DbContextOptions
untuk setiap pengujian adalah menggunakan DbContextOptionsBuilder:
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb");
using (var db = new AppDbContext(optionsBuilder.Options))
{
// Use the db here in the unit test.
}
Masalah dengan pendekatan ini adalah bahwa setiap pengujian menerima database dalam status apa pun yang ditinggalkan oleh pengujian sebelumnya. Ini bisa bermasalah ketika mencoba menulis tes unit atom yang tidak mengganggu satu sama lain. Untuk memaksa AppDbContext
penggunaan konteks database baru untuk setiap pengujian, berikan DbContextOptions
instans yang didasarkan pada penyedia layanan baru. Aplikasi pengujian menunjukkan cara melakukan ini menggunakan metode TestDbContextOptions
kelasnya Utilities
(tests/RazorPagesTestSample.Tests/Utilities/Utilities.cs
):
public static DbContextOptions<AppDbContext> TestDbContextOptions()
{
// Create a new service provider to create a new in-memory database.
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
// Create a new options instance using an in-memory database and
// IServiceProvider that the context should resolve all of its
// services from.
var builder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb")
.UseInternalServiceProvider(serviceProvider);
return builder.Options;
}
DbContextOptions
Menggunakan dalam pengujian unit DAL memungkinkan setiap pengujian berjalan secara atomik dengan instans database baru:
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Use the db here in the unit test.
}
Setiap metode pengujian di DataAccessLayerTest
kelas (UnitTests/DataAccessLayerTest.cs
) mengikuti pola Arrange-Act-Assert serupa:
- Arrange: Database dikonfigurasi untuk pengujian dan/atau hasil yang diharapkan ditentukan.
- Act: Pengujian dijalankan.
- Pernyataan: Pernyataan dibuat untuk menentukan apakah hasil pengujian berhasil.
Misalnya, DeleteMessageAsync
metode ini bertanggung jawab untuk menghapus satu pesan yang diidentifikasi oleh Id
(src/RazorPagesTestSample/Data/AppDbContext.cs
):
public async virtual Task DeleteMessageAsync(int id)
{
var message = await Messages.FindAsync(id);
if (message != null)
{
Messages.Remove(message);
await SaveChangesAsync();
}
}
Ada dua tes untuk metode ini. Satu pengujian memeriksa bahwa metode menghapus pesan saat pesan ada dalam database. Metode lain menguji bahwa database tidak berubah jika pesan Id
untuk penghapusan tidak ada. Metode DeleteMessageAsync_MessageIsDeleted_WhenMessageIsFound
ini ditunjukkan di bawah ini:
[Fact]
public async Task DeleteMessageAsync_MessageIsDeleted_WhenMessageIsFound()
{
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Arrange
var seedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(seedMessages);
await db.SaveChangesAsync();
var recId = 1;
var expectedMessages =
seedMessages.Where(message => message.Id != recId).ToList();
// Act
await db.DeleteMessageAsync(recId);
// Assert
var actualMessages = await db.Messages.AsNoTracking().ToListAsync();
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
}
}
Pertama, metode melakukan langkah Susun, di mana persiapan untuk langkah Undang-Undang berlangsung. Pesan seeding diperoleh dan disimpan di seedMessages
. Pesan seeding disimpan ke dalam database. Pesan dengan Id
dari 1
diatur untuk dihapus. DeleteMessageAsync
Ketika metode dijalankan, pesan yang diharapkan harus memiliki semua pesan kecuali untuk pesan dengan Id
.1
Variabel expectedMessages
mewakili hasil yang diharapkan ini.
// Arrange
var seedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(seedMessages);
await db.SaveChangesAsync();
var recId = 1;
var expectedMessages =
seedMessages.Where(message => message.Id != recId).ToList();
Metode bertindak: Metode DeleteMessageAsync
dijalankan melewati di recId
dari 1
:
// Act
await db.DeleteMessageAsync(recId);
Akhirnya, metode memperoleh Messages
dari konteks dan membandingkannya expectedMessages
dengan menegaskan bahwa keduanya sama:
// Assert
var actualMessages = await db.Messages.AsNoTracking().ToListAsync();
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
Untuk membandingkan bahwa keduanya List<Message>
sama:
- Pesan diurutkan oleh
Id
. - Pasangan pesan dibandingkan pada
Text
properti .
Metode pengujian serupa, DeleteMessageAsync_NoMessageIsDeleted_WhenMessageIsNotFound
memeriksa hasil upaya untuk menghapus pesan yang tidak ada. Dalam hal ini, pesan yang diharapkan dalam database harus sama dengan pesan aktual setelah DeleteMessageAsync
metode dijalankan. Seharusnya tidak ada perubahan pada konten database:
[Fact]
public async Task DeleteMessageAsync_NoMessageIsDeleted_WhenMessageIsNotFound()
{
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Arrange
var expectedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(expectedMessages);
await db.SaveChangesAsync();
var recId = 4;
// Act
try
{
await db.DeleteMessageAsync(recId);
}
catch
{
// recId doesn't exist
}
// Assert
var actualMessages = await db.Messages.AsNoTracking().ToListAsync();
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
}
}
Pengujian unit metode model halaman
Serangkaian pengujian unit lainnya bertanggung jawab atas pengujian metode model halaman. Di aplikasi pesan, model halaman Indeks ditemukan di IndexModel
kelas di src/RazorPagesTestSample/Pages/Index.cshtml.cs
.
Metode model halaman | Fungsi |
---|---|
OnGetAsync |
Mendapatkan pesan dari DAL untuk UI menggunakan metode .GetMessagesAsync |
OnPostAddMessageAsync |
Jika ModelState valid, panggilan AddMessageAsync untuk menambahkan pesan ke database. |
OnPostDeleteAllMessagesAsync |
DeleteAllMessagesAsync Panggilan untuk menghapus semua pesan dalam database. |
OnPostDeleteMessageAsync |
DeleteMessageAsync Menjalankan untuk menghapus pesan dengan yang Id ditentukan. |
OnPostAnalyzeMessagesAsync |
Jika satu atau beberapa pesan berada dalam database, menghitung jumlah rata-rata kata per pesan. |
Metode model halaman diuji menggunakan tujuh pengujian di IndexPageTests
kelas (tests/RazorPagesTestSample.Tests/UnitTests/IndexPageTests.cs
). Pengujian menggunakan pola Arrange-Assert-Act yang sudah dikenal. Pengujian ini berfokus pada:
- Menentukan apakah metode mengikuti perilaku yang benar ketika ModelState tidak valid.
- Mengonfirmasi metode menghasilkan yang benar IActionResult.
- Memeriksa apakah penetapan nilai properti dibuat dengan benar.
Grup pengujian ini sering meniru metode DAL untuk menghasilkan data yang diharapkan untuk langkah Undang-Undang tempat metode model halaman dijalankan. Misalnya, GetMessagesAsync
metode ditiru AppDbContext
untuk menghasilkan output. Ketika metode model halaman menjalankan metode ini, tiruan mengembalikan hasilnya. Data tidak berasal dari database. Ini menciptakan kondisi pengujian yang dapat diprediksi dan dapat diandalkan untuk menggunakan DAL dalam pengujian model halaman.
Pengujian OnGetAsync_PopulatesThePageModel_WithAListOfMessages
menunjukkan bagaimana metode ditiru GetMessagesAsync
untuk model halaman:
var mockAppDbContext = new Mock<AppDbContext>(optionsBuilder.Options);
var expectedMessages = AppDbContext.GetSeedingMessages();
mockAppDbContext.Setup(
db => db.GetMessagesAsync()).Returns(Task.FromResult(expectedMessages));
var pageModel = new IndexModel(mockAppDbContext.Object);
OnGetAsync
Ketika metode dijalankan dalam langkah UU, metode ini memanggil metode model GetMessagesAsync
halaman.
Langkah Undang-Undang pengujian unit (tests/RazorPagesTestSample.Tests/UnitTests/IndexPageTests.cs
):
// Act
await pageModel.OnGetAsync();
IndexPage
metode model OnGetAsync
halaman (src/RazorPagesTestSample/Pages/Index.cshtml.cs
):
public async Task OnGetAsync()
{
Messages = await _db.GetMessagesAsync();
}
Metode GetMessagesAsync
dalam DAL tidak mengembalikan hasil untuk panggilan metode ini. Versi metode yang ditidakan mengembalikan hasilnya.
Pada langkah tersebut Assert
, pesan aktual (actualMessages
) ditetapkan dari Messages
properti model halaman. Pemeriksaan jenis juga dilakukan saat pesan ditetapkan. Pesan yang diharapkan dan aktual dibandingkan dengan propertinya Text
. Pengujian menegaskan bahwa kedua List<Message>
instans berisi pesan yang sama.
// Assert
var actualMessages = Assert.IsAssignableFrom<List<Message>>(pageModel.Messages);
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
Pengujian lain dalam grup ini membuat objek model halaman yang menyertakan DefaultHttpContext, , ModelStateDictionaryan ActionContext untuk membuat PageContext
, ViewDataDictionary
, dan PageContext
. Ini berguna dalam melakukan tes. Misalnya, aplikasi pesan membuat ModelState
kesalahan dengan AddModelError untuk memeriksa apakah valid PageResult dikembalikan saat OnPostAddMessageAsync
dijalankan:
[Fact]
public async Task OnPostAddMessageAsync_ReturnsAPageResult_WhenModelStateIsInvalid()
{
// Arrange
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb");
var mockAppDbContext = new Mock<AppDbContext>(optionsBuilder.Options);
var expectedMessages = AppDbContext.GetSeedingMessages();
mockAppDbContext.Setup(db => db.GetMessagesAsync()).Returns(Task.FromResult(expectedMessages));
var httpContext = new DefaultHttpContext();
var modelState = new ModelStateDictionary();
var actionContext = new ActionContext(httpContext, new RouteData(), new PageActionDescriptor(), modelState);
var modelMetadataProvider = new EmptyModelMetadataProvider();
var viewData = new ViewDataDictionary(modelMetadataProvider, modelState);
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>());
var pageContext = new PageContext(actionContext)
{
ViewData = viewData
};
var pageModel = new IndexModel(mockAppDbContext.Object)
{
PageContext = pageContext,
TempData = tempData,
Url = new UrlHelper(actionContext)
};
pageModel.ModelState.AddModelError("Message.Text", "The Text field is required.");
// Act
var result = await pageModel.OnPostAddMessageAsync();
// Assert
Assert.IsType<PageResult>(result);
}
Sumber Daya Tambahan:
ASP.NET Core mendukung pengujian Razor unit aplikasi Pages. Pengujian lapisan akses data (DAL) dan model halaman membantu memastikan:
- Bagian dari Razor aplikasi Pages bekerja secara independen dan bersama-sama sebagai unit selama konstruksi aplikasi.
- Kelas dan metode memiliki cakupan tanggung jawab yang terbatas.
- Dokumentasi tambahan ada tentang bagaimana aplikasi harus berakibat.
- Regresi, yang merupakan kesalahan yang dibawa oleh pembaruan pada kode, ditemukan selama pembuatan dan penyebaran otomatis.
Topik ini mengasumsikan bahwa Anda memiliki pemahaman Razor dasar tentang aplikasi Pages dan pengujian unit. Jika Anda tidak terbiasa dengan Razor aplikasi Pages atau konsep pengujian, lihat topik berikut:
- Pengantar Razor Halaman di ASP.NET Core
- Tutorial: Mulai menggunakan Razor Pages di ASP.NET Core
- Pengujian unit C# di .NET Core menggunakan uji dotnet dan xUnit
Melihat atau mengunduh kode sampel (cara mengunduh)
Proyek sampel terdiri dari dua aplikasi:
App | Folder proyek | Deskripsi |
---|---|---|
Aplikasi pesan | src/RazorPagesTestSample | Memungkinkan pengguna menambahkan pesan, menghapus satu pesan, menghapus semua pesan, dan menganalisis pesan (menemukan jumlah rata-rata kata per pesan). |
Menguji aplikasi | tests/RazorPagesTestSample.Tests | Digunakan untuk menguji unit model halaman DAL dan Indeks aplikasi pesan. |
Pengujian dapat dijalankan menggunakan fitur pengujian bawaan IDE, seperti Visual Studio. Jika menggunakan Visual Studio Code atau baris perintah, jalankan perintah berikut pada prompt perintah di folder tests/RazorPagesTestSample.Tests :
dotnet test
Organisasi aplikasi pesan
Aplikasi pesan adalah Razor sistem pesan Pages dengan karakteristik berikut:
- Halaman Indeks aplikasi (
Pages/Index.cshtml
danPages/Index.cshtml.cs
) menyediakan metode UI dan model halaman untuk mengontrol penambahan, penghapusan, dan analisis pesan (temukan jumlah rata-rata kata per pesan). - Pesan dijelaskan oleh
Message
kelas (Data/Message.cs
) dengan dua properti:Id
(kunci) danText
(pesan). PropertiText
diperlukan dan dibatasi hingga 200 karakter. - Pesan disimpan menggunakan database dalam memori Entity Framework†.
- Aplikasi ini berisi DAL di kelas konteks databasenya,
AppDbContext
(Data/AppDbContext.cs
). Metode DAL ditandaivirtual
, yang memungkinkan mocking metode untuk digunakan dalam pengujian. - Jika database kosong pada startup aplikasi, penyimpanan pesan diinisialisasi dengan tiga pesan. Pesan benih ini juga digunakan dalam pengujian.
† Topik EF, Uji dengan InMemory, menjelaskan cara menggunakan database dalam memori untuk pengujian dengan MSTest. Topik ini menggunakan kerangka kerja pengujian xUnit . Konsep pengujian dan implementasi pengujian di berbagai kerangka kerja pengujian serupa tetapi tidak identik.
Meskipun aplikasi sampel tidak menggunakan pola repositori dan bukan contoh pola Unit kerja (UoW) yang efektif, Razor Pages mendukung pola pengembangan ini. Untuk informasi selengkapnya, lihat Merancang lapisan persistensi infrastruktur dan Logika pengontrol Pengujian di ASP.NET Core (sampel mengimplementasikan pola repositori).
Menguji organisasi aplikasi
Aplikasi pengujian adalah aplikasi konsol di dalam folder tests/RazorPagesTestSample.Tests .
Menguji folder aplikasi | Deskripsi |
---|---|
UnitTests |
|
Utilitas | Berisi metode yang TestDbContextOptions digunakan untuk membuat opsi konteks database baru untuk setiap pengujian unit DAL sehingga database diatur ulang ke kondisi garis besarnya untuk setiap pengujian. |
Kerangka kerja pengujian adalah xUnit. Kerangka kerja tiruan objek adalah Moq.
Pengujian unit lapisan akses data (DAL)
Aplikasi pesan memiliki DAL dengan empat metode yang terkandung dalam AppDbContext
kelas (src/RazorPagesTestSample/Data/AppDbContext.cs
). Setiap metode memiliki satu atau dua pengujian unit di aplikasi pengujian.
Metode DAL | Fungsi |
---|---|
GetMessagesAsync |
Mendapatkan dari database yang List<Message> diurutkan menurut Text properti . |
AddMessageAsync |
Message Menambahkan ke database. |
DeleteAllMessagesAsync |
Menghapus semua Message entri dari database. |
DeleteMessageAsync |
Menghapus satu Message dari database dengan Id . |
Pengujian unit DAL diperlukan DbContextOptions saat membuat baru AppDbContext
untuk setiap pengujian. Salah satu pendekatan untuk membuat DbContextOptions
untuk setiap pengujian adalah menggunakan DbContextOptionsBuilder:
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb");
using (var db = new AppDbContext(optionsBuilder.Options))
{
// Use the db here in the unit test.
}
Masalah dengan pendekatan ini adalah bahwa setiap pengujian menerima database dalam status apa pun yang ditinggalkan oleh pengujian sebelumnya. Ini bisa bermasalah ketika mencoba menulis tes unit atom yang tidak mengganggu satu sama lain. Untuk memaksa AppDbContext
penggunaan konteks database baru untuk setiap pengujian, berikan DbContextOptions
instans yang didasarkan pada penyedia layanan baru. Aplikasi pengujian menunjukkan cara melakukan ini menggunakan metode TestDbContextOptions
kelasnya Utilities
(tests/RazorPagesTestSample.Tests/Utilities/Utilities.cs
):
public static DbContextOptions<AppDbContext> TestDbContextOptions()
{
// Create a new service provider to create a new in-memory database.
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
// Create a new options instance using an in-memory database and
// IServiceProvider that the context should resolve all of its
// services from.
var builder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb")
.UseInternalServiceProvider(serviceProvider);
return builder.Options;
}
DbContextOptions
Menggunakan dalam pengujian unit DAL memungkinkan setiap pengujian berjalan secara atomik dengan instans database baru:
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Use the db here in the unit test.
}
Setiap metode pengujian di DataAccessLayerTest
kelas (UnitTests/DataAccessLayerTest.cs
) mengikuti pola Arrange-Act-Assert serupa:
- Arrange: Database dikonfigurasi untuk pengujian dan/atau hasil yang diharapkan ditentukan.
- Act: Pengujian dijalankan.
- Pernyataan: Pernyataan dibuat untuk menentukan apakah hasil pengujian berhasil.
Misalnya, DeleteMessageAsync
metode ini bertanggung jawab untuk menghapus satu pesan yang diidentifikasi oleh Id
(src/RazorPagesTestSample/Data/AppDbContext.cs
):
public async virtual Task DeleteMessageAsync(int id)
{
var message = await Messages.FindAsync(id);
if (message != null)
{
Messages.Remove(message);
await SaveChangesAsync();
}
}
Ada dua tes untuk metode ini. Satu pengujian memeriksa bahwa metode menghapus pesan saat pesan ada dalam database. Metode lain menguji bahwa database tidak berubah jika pesan Id
untuk penghapusan tidak ada. Metode DeleteMessageAsync_MessageIsDeleted_WhenMessageIsFound
ini ditunjukkan di bawah ini:
[Fact]
public async Task DeleteMessageAsync_MessageIsDeleted_WhenMessageIsFound()
{
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Arrange
var seedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(seedMessages);
await db.SaveChangesAsync();
var recId = 1;
var expectedMessages =
seedMessages.Where(message => message.Id != recId).ToList();
// Act
await db.DeleteMessageAsync(recId);
// Assert
var actualMessages = await db.Messages.AsNoTracking().ToListAsync();
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
}
}
Pertama, metode melakukan langkah Susun, di mana persiapan untuk langkah Undang-Undang berlangsung. Pesan seeding diperoleh dan disimpan di seedMessages
. Pesan seeding disimpan ke dalam database. Pesan dengan Id
dari 1
diatur untuk dihapus. DeleteMessageAsync
Ketika metode dijalankan, pesan yang diharapkan harus memiliki semua pesan kecuali untuk pesan dengan Id
.1
Variabel expectedMessages
mewakili hasil yang diharapkan ini.
// Arrange
var seedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(seedMessages);
await db.SaveChangesAsync();
var recId = 1;
var expectedMessages =
seedMessages.Where(message => message.Id != recId).ToList();
Metode bertindak: Metode DeleteMessageAsync
dijalankan melewati di recId
dari 1
:
// Act
await db.DeleteMessageAsync(recId);
Akhirnya, metode memperoleh Messages
dari konteks dan membandingkannya expectedMessages
dengan menegaskan bahwa keduanya sama:
// Assert
var actualMessages = await db.Messages.AsNoTracking().ToListAsync();
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
Untuk membandingkan bahwa keduanya List<Message>
sama:
- Pesan diurutkan oleh
Id
. - Pasangan pesan dibandingkan pada
Text
properti .
Metode pengujian serupa, DeleteMessageAsync_NoMessageIsDeleted_WhenMessageIsNotFound
memeriksa hasil upaya untuk menghapus pesan yang tidak ada. Dalam hal ini, pesan yang diharapkan dalam database harus sama dengan pesan aktual setelah DeleteMessageAsync
metode dijalankan. Seharusnya tidak ada perubahan pada konten database:
[Fact]
public async Task DeleteMessageAsync_NoMessageIsDeleted_WhenMessageIsNotFound()
{
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Arrange
var expectedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(expectedMessages);
await db.SaveChangesAsync();
var recId = 4;
// Act
await db.DeleteMessageAsync(recId);
// Assert
var actualMessages = await db.Messages.AsNoTracking().ToListAsync();
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
}
}
Pengujian unit metode model halaman
Serangkaian pengujian unit lainnya bertanggung jawab atas pengujian metode model halaman. Di aplikasi pesan, model halaman Indeks ditemukan di IndexModel
kelas di src/RazorPagesTestSample/Pages/Index.cshtml.cs
.
Metode model halaman | Fungsi |
---|---|
OnGetAsync |
Mendapatkan pesan dari DAL untuk UI menggunakan metode .GetMessagesAsync |
OnPostAddMessageAsync |
Jika ModelState valid, panggilan AddMessageAsync untuk menambahkan pesan ke database. |
OnPostDeleteAllMessagesAsync |
DeleteAllMessagesAsync Panggilan untuk menghapus semua pesan dalam database. |
OnPostDeleteMessageAsync |
DeleteMessageAsync Menjalankan untuk menghapus pesan dengan yang Id ditentukan. |
OnPostAnalyzeMessagesAsync |
Jika satu atau beberapa pesan berada dalam database, menghitung jumlah rata-rata kata per pesan. |
Metode model halaman diuji menggunakan tujuh pengujian di IndexPageTests
kelas (tests/RazorPagesTestSample.Tests/UnitTests/IndexPageTests.cs
). Pengujian menggunakan pola Arrange-Assert-Act yang sudah dikenal. Pengujian ini berfokus pada:
- Menentukan apakah metode mengikuti perilaku yang benar ketika ModelState tidak valid.
- Mengonfirmasi metode menghasilkan yang benar IActionResult.
- Memeriksa apakah penetapan nilai properti dibuat dengan benar.
Grup pengujian ini sering meniru metode DAL untuk menghasilkan data yang diharapkan untuk langkah Undang-Undang tempat metode model halaman dijalankan. Misalnya, GetMessagesAsync
metode ditiru AppDbContext
untuk menghasilkan output. Ketika metode model halaman menjalankan metode ini, tiruan mengembalikan hasilnya. Data tidak berasal dari database. Ini menciptakan kondisi pengujian yang dapat diprediksi dan dapat diandalkan untuk menggunakan DAL dalam pengujian model halaman.
Pengujian OnGetAsync_PopulatesThePageModel_WithAListOfMessages
menunjukkan bagaimana metode ditiru GetMessagesAsync
untuk model halaman:
var mockAppDbContext = new Mock<AppDbContext>(optionsBuilder.Options);
var expectedMessages = AppDbContext.GetSeedingMessages();
mockAppDbContext.Setup(
db => db.GetMessagesAsync()).Returns(Task.FromResult(expectedMessages));
var pageModel = new IndexModel(mockAppDbContext.Object);
OnGetAsync
Ketika metode dijalankan dalam langkah UU, metode ini memanggil metode model GetMessagesAsync
halaman.
Langkah Undang-Undang pengujian unit (tests/RazorPagesTestSample.Tests/UnitTests/IndexPageTests.cs
):
// Act
await pageModel.OnGetAsync();
IndexPage
metode model OnGetAsync
halaman (src/RazorPagesTestSample/Pages/Index.cshtml.cs
):
public async Task OnGetAsync()
{
Messages = await _db.GetMessagesAsync();
}
Metode GetMessagesAsync
dalam DAL tidak mengembalikan hasil untuk panggilan metode ini. Versi metode yang ditidakan mengembalikan hasilnya.
Pada langkah tersebut Assert
, pesan aktual (actualMessages
) ditetapkan dari Messages
properti model halaman. Pemeriksaan jenis juga dilakukan saat pesan ditetapkan. Pesan yang diharapkan dan aktual dibandingkan dengan propertinya Text
. Pengujian menegaskan bahwa kedua List<Message>
instans berisi pesan yang sama.
// Assert
var actualMessages = Assert.IsAssignableFrom<List<Message>>(pageModel.Messages);
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
Pengujian lain dalam grup ini membuat objek model halaman yang menyertakan DefaultHttpContext, , ModelStateDictionaryan ActionContext untuk membuat PageContext
, ViewDataDictionary
, dan PageContext
. Ini berguna dalam melakukan tes. Misalnya, aplikasi pesan membuat ModelState
kesalahan dengan AddModelError untuk memeriksa apakah valid PageResult dikembalikan saat OnPostAddMessageAsync
dijalankan:
[Fact]
public async Task OnPostAddMessageAsync_ReturnsAPageResult_WhenModelStateIsInvalid()
{
// Arrange
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb");
var mockAppDbContext = new Mock<AppDbContext>(optionsBuilder.Options);
var expectedMessages = AppDbContext.GetSeedingMessages();
mockAppDbContext.Setup(db => db.GetMessagesAsync()).Returns(Task.FromResult(expectedMessages));
var httpContext = new DefaultHttpContext();
var modelState = new ModelStateDictionary();
var actionContext = new ActionContext(httpContext, new RouteData(), new PageActionDescriptor(), modelState);
var modelMetadataProvider = new EmptyModelMetadataProvider();
var viewData = new ViewDataDictionary(modelMetadataProvider, modelState);
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>());
var pageContext = new PageContext(actionContext)
{
ViewData = viewData
};
var pageModel = new IndexModel(mockAppDbContext.Object)
{
PageContext = pageContext,
TempData = tempData,
Url = new UrlHelper(actionContext)
};
pageModel.ModelState.AddModelError("Message.Text", "The Text field is required.");
// Act
var result = await pageModel.OnPostAddMessageAsync();
// Assert
Assert.IsType<PageResult>(result);
}
Sumber Daya Tambahan:
- Pengujian unit C# di .NET Core menggunakan uji dotnet dan xUnit
- Menguji logika pengontrol di ASP.NET Core
- Unit Uji Kode Anda (Visual Studio)
- Pengujian integrasi di ASP.NET Core
- xUnit.net
- Mulai menggunakan xUnit.net: Menggunakan .NET Core dengan baris perintah .NET SDK
- Moq
- Mulai Cepat Moq
- JustMockLite: Kerangka kerja tiruan untuk pengembang .NET. (Tidak dipertahankan atau didukung oleh Microsoft.)
ASP.NET Core