Razor ASP.NET Core'da sayfalar birim testleri
ASP.NET Core, Pages uygulamalarının birim testlerini Razor destekler. Veri erişim katmanı (DAL) ve sayfa modellerinin testleri şunların sağlanmasına yardımcı olur:
- Sayfalar uygulamasının Razor bölümleri, uygulama oluşturma sırasında bağımsız olarak ve bir birim olarak birlikte çalışır.
- Sınıflar ve yöntemler sınırlı sorumluluk kapsamlarına sahiptir.
- Uygulamanın nasıl davranması gerektiğine ilişkin ek belgeler vardır.
- Kod güncelleştirmelerinin getirdiği hatalar olan regresyonlar, otomatik derleme ve dağıtım sırasında bulunur.
Bu konu başlığında Sayfalar uygulamaları ve birim testleri hakkında Razor temel bilgilere sahip olduğunuz varsayılır. Sayfalar uygulamaları veya test kavramları hakkında Razor bilginiz yoksa aşağıdaki konulara bakın:
- ASP.NET Core'da Sayfalara Razor Giriş
- Öğretici: ASP.NET Core'da Razor Pages'i kullanmaya başlama
- Dotnet test ve xUnit kullanarak .NET Core'da C# birim testi
Örnek kodu görüntüleme veya indirme (indirme)
Örnek proje iki uygulamadan oluşur:
Uygulama | Proje klasörü | Açıklama |
---|---|---|
İleti uygulaması | src/RazorPagesTestSample | Kullanıcının ileti eklemesine, bir iletiyi silmesine, tüm iletileri silmesine ve iletileri analiz etmesine izin verir (ileti başına ortalama sözcük sayısını bulur). |
Test uygulaması | tests/RazorPagesTestSample.Tests | İleti uygulamasının DAL ve Dizin sayfası modelini birim testi için kullanılır. |
Testler, Visual Studio gibi bir IDE'nin yerleşik test özellikleri kullanılarak çalıştırılabilir. Visual Studio Code veya komut satırı kullanıyorsanız, tests/RazorPagesTestSample.Tests klasöründeki bir komut isteminde aşağıdaki komutu yürütür:
dotnet test
İleti uygulaması kuruluşu
İleti uygulaması, aşağıdaki özelliklere sahip bir Razor Sayfalar ileti sistemidir:
- Uygulamanın (
Pages/Index.cshtml
vePages/Index.cshtml.cs
) Dizin sayfası, iletilerin eklenmesini, silinmesini ve analizini denetlemek için bir kullanıcı arabirimi ve sayfa modeli yöntemleri sağlar (ileti başına ortalama sözcük sayısını bulur). - bir ileti sınıfı
Data/Message.cs
() tarafındanMessage
iki özelliğe sahip olarak açıklanır:Id
(anahtar) veText
(ileti).Text
özelliği gereklidir ve 200 karakterle sınırlıdır. - İletiler Entity Framework'ün bellek içi veritabanı† kullanılarak depolanır.
- Uygulama, veritabanı bağlam sınıfında
AppDbContext
Data/AppDbContext.cs
() bir DAL içerir. DAL yöntemleri, testlerde kullanılmak üzere yöntemlerin sahtesini oluşturmanızı sağlayan olarak işaretlenirvirtual
. - Uygulama başlangıcında veritabanı boşsa, ileti deposu üç iletiyle başlatılır. Bu dağıtılmış iletiler testlerde de kullanılır.
†InMemory ile Test et ef konusu, MSTest ile testler için bellek içi veritabanının nasıl kullanılacağını açıklar. Bu konu, xUnit test çerçevesini kullanır. Farklı test çerçevelerindeki test kavramları ve test uygulamaları benzerdir ancak aynı değildir.
Örnek uygulama depo desenini kullanmasa ve çalışma birimi (UoW) deseninin etkili bir örneği olmasa da, Razor Sayfalar bu geliştirme desenlerini destekler. Daha fazla bilgi için bkz . Altyapı kalıcılık katmanını tasarlama ve ASP.NET Core'da test denetleyicisi mantığı (örnek depo düzenini uygular).
Uygulama kuruluşunu test et
Test uygulaması tests/RazorPagesTestSample.Tests klasörünün içindeki bir konsol uygulamasıdır.
Test uygulaması klasörü | Açıklama |
---|---|
UnitTests |
|
Yardımcı program | Veritabanının TestDbContextOptions her test için temel koşuluna sıfırlanması için her DAL birim testi için yeni veritabanı bağlam seçenekleri oluşturmak için kullanılan yöntemi içerir. |
Test çerçevesi xUnit'tir. Nesne sahte çerçevesi Moq'tır.
Veri erişim katmanının birim testleri (DAL)
İleti uygulaması, sınıfında (src/RazorPagesTestSample/Data/AppDbContext.cs
) bulunan dört yöntem içeren bir DAL'a AppDbContext
sahiptir. Her yöntemin test uygulamasında bir veya iki birim testi vardır.
DAL yöntemi | İşlev |
---|---|
GetMessagesAsync |
özelliğine göre sıralanmış veritabanından Text bir List<Message> alır. |
AddMessageAsync |
Veritabanına bir Message ekler. |
DeleteAllMessagesAsync |
Veritabanındaki tüm Message girdileri siler. |
DeleteMessageAsync |
veritabanından tek Message bir öğesini tarafından Id siler. |
DAL'nin birim testleri, her test için yeni AppDbContext
bir oluşturma işlemini gerektirirDbContextOptions. Her test için oluşturma DbContextOptions
yaklaşımlarından biri kullanmaktır DbContextOptionsBuilder:
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb");
using (var db = new AppDbContext(optionsBuilder.Options))
{
// Use the db here in the unit test.
}
Bu yaklaşımdaki sorun, her testin veritabanını önceki testte bıraktığı durumda almasıdır. Bu, birbiriyle karışmadan atomik birim testleri yazmaya çalışırken sorun olabilir. öğesini her test için yeni bir veritabanı bağlamı kullanmaya zorlamak AppDbContext
için yeni bir hizmet sağlayıcısını temel alan bir DbContextOptions
örnek sağlayın. Test uygulaması, bunun sınıf yöntemini TestDbContextOptions
(tests/RazorPagesTestSample.Tests/Utilities/Utilities.cs
) kullanarak Utilities
nasıl yapılacağını gösterir:
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;
}
DAL birim testlerinde komutunun DbContextOptions
kullanılması, her testin yeni bir veritabanı örneğiyle atomik olarak çalışmasına olanak tanır:
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Use the db here in the unit test.
}
(UnitTests/DataAccessLayerTest.cs
) sınıfındaki DataAccessLayerTest
her test yöntemi benzer bir Arrange-Act-Assert desenini izler:
- Düzenleme: Veritabanı test için yapılandırılır ve/veya beklenen sonuç tanımlanır.
- Eylem: Test yürütülür.
- Onay: Test sonucunun başarılı olup olmadığını belirlemek için onaylar yapılır.
Örneğin yöntemi, DeleteMessageAsync
(src/RazorPagesTestSample/Data/AppDbContext.cs
) tarafından Id
tanımlanan tek bir iletiyi kaldırmakla sorumludur:
public async virtual Task DeleteMessageAsync(int id)
{
var message = await Messages.FindAsync(id);
if (message != null)
{
Messages.Remove(message);
await SaveChangesAsync();
}
}
Bu yöntem için iki test vardır. Bir test, ileti veritabanında mevcut olduğunda yöntemin bir iletiyi silip silmediğini denetler. Diğer yöntem, silme iletisi Id
yoksa veritabanının değişmediğini test eder. DeleteMessageAsync_MessageIsDeleted_WhenMessageIsFound
yöntemi aşağıda gösterilmiştir:
[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));
}
}
İlk olarak, yöntem Düzenleme adımını gerçekleştirir ve burada Act adımı için hazırlık gerçekleştirilir. Tohumlama iletileri alınır ve içinde seedMessages
tutulur. Tohumlama iletileri veritabanına kaydedilir. içeren ileti Id
1
silinmek üzere ayarlanmıştır. DeleteMessageAsync
yöntemi yürütülürken, beklenen iletilerde , ile olan dışında Id
1
tüm iletiler bulunmalıdır. değişkeni bu expectedMessages
beklenen sonucu temsil eder.
// Arrange
var seedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(seedMessages);
await db.SaveChangesAsync();
var recId = 1;
var expectedMessages =
seedMessages.Where(message => message.Id != recId).ToList();
yöntemi şu şekilde davranır: DeleteMessageAsync
yöntemi, öğesini geçirerek recId
1
yürütülür:
// Act
await db.DeleteMessageAsync(recId);
Son olarak, yöntemi bağlamdan öğesini alır Messages
ve ikisinin expectedMessages
eşit olduğunu onaylama işlemiyle karşılaştırır:
// 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));
İkisinin aynı olduğunu List<Message>
karşılaştırmak için:
- İletiler tarafından
Id
sıralanır. - İleti çiftleri özelliğinde
Text
karşılaştırılır.
Benzer bir test yöntemi, DeleteMessageAsync_NoMessageIsDeleted_WhenMessageIsNotFound
var olmayan bir iletiyi silme girişiminin sonucunu denetler. Bu durumda, yöntem yürütüldükten sonra veritabanında beklenen iletiler gerçek iletilere DeleteMessageAsync
eşit olmalıdır. Veritabanının içeriğinde değişiklik yapılmamalıdır:
[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));
}
}
Sayfa modeli yöntemlerinin birim testleri
Başka bir birim testi kümesi de sayfa modeli yöntemlerinin testlerinden sorumludur. İleti uygulamasında, Dizin sayfası modelleri sınıfında IndexModel
src/RazorPagesTestSample/Pages/Index.cshtml.cs
bulunur.
Sayfa modeli yöntemi | İşlev |
---|---|
OnGetAsync |
yöntemini kullanarak GetMessagesAsync kullanıcı arabirimi için DAL'den iletileri alır. |
OnPostAddMessageAsync |
ModelState geçerliyse, veritabanına ileti eklemek için çağrılarAddMessageAsync . |
OnPostDeleteAllMessagesAsync |
Veritabanındaki tüm iletileri silmek için çağrılar DeleteAllMessagesAsync . |
OnPostDeleteMessageAsync |
DeleteMessageAsync Belirtilen ile bir iletiyi silmek için yürütürId . |
OnPostAnalyzeMessagesAsync |
Veritabanında bir veya daha fazla ileti varsa, ileti başına ortalama sözcük sayısını hesaplar. |
Sayfa modeli yöntemleri(tests/RazorPagesTestSample.Tests/UnitTests/IndexPageTests.cs
sınıfında yedi test IndexPageTests
kullanılarak test edilir. Testler tanıdık Düzenleme-Assert-Act desenini kullanır. Bu testler şunlara odaklanır:
- ModelState geçersiz olduğunda yöntemlerin doğru davranışı izleyip izlemediğini belirleme.
- Yöntemlerin doğru şekilde üretildiğini IActionResultonaylama.
- Özellik değeri atamalarının doğru yapılarak denetleniyor.
Bu test grubu genellikle bir sayfa modeli yönteminin yürütüldüğü Act adımı için beklenen verileri üretmek üzere DAL yöntemleriyle dalga geçer. Örneğin, GetMessagesAsync
yöntemi AppDbContext
çıkış üretmek için sahtedir. Bir sayfa modeli yöntemi bu yöntemi yürüttüğünde, sahte sonuç döndürür. Veriler veritabanından gelmez. Bu, DAL'yi sayfa modeli testlerinde kullanmak için öngörülebilir, güvenilir test koşulları oluşturur.
Test, OnGetAsync_PopulatesThePageModel_WithAListOfMessages
yöntemin GetMessagesAsync
sayfa modeli için nasıl sahte olduğunu gösterir:
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
Yöntem Act adımında yürütülürken sayfa modelinin GetMessagesAsync
yöntemini çağırır.
Birim testi Yasası adımı (tests/RazorPagesTestSample.Tests/UnitTests/IndexPageTests.cs
):
// Act
await pageModel.OnGetAsync();
IndexPage
sayfa modelinin OnGetAsync
yöntemi (src/RazorPagesTestSample/Pages/Index.cshtml.cs
):
public async Task OnGetAsync()
{
Messages = await _db.GetMessagesAsync();
}
GetMessagesAsync
DAL içindeki yöntemi, bu yöntem çağrısının sonucunu döndürmez. Yöntemin sahte sürümü sonucu döndürür.
Assert
Adımda, gerçek iletiler (actualMessages
) sayfa modelinin Messages
özelliğinden atanır. İletiler atandığında bir tür denetimi de gerçekleştirilir. Beklenen ve gerçek iletiler özellikleriyle Text
karşılaştırılır. Test, iki List<Message>
örneğin aynı iletileri içerdiğini onaylar.
// 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));
Bu gruptaki diğer testler, , ActionContext ModelStateDictionaryViewDataDictionary
bir ve PageContext
oluşturmak için PageContext
, , içeren sayfa modeli nesneleri DefaultHttpContextoluşturur. Bunlar, testlerin yürütülmesinde yararlıdır. Örneğin, ileti uygulaması yürütülürken OnPostAddMessageAsync
geçerli PageResult bir döndürüldüğünü denetlemek için ile AddModelError bir ModelState
hata oluşturur:
[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);
}
Ek kaynaklar
ASP.NET Core, Pages uygulamalarının birim testlerini Razor destekler. Veri erişim katmanı (DAL) ve sayfa modellerinin testleri şunların sağlanmasına yardımcı olur:
- Sayfalar uygulamasının Razor bölümleri, uygulama oluşturma sırasında bağımsız olarak ve bir birim olarak birlikte çalışır.
- Sınıflar ve yöntemler sınırlı sorumluluk kapsamlarına sahiptir.
- Uygulamanın nasıl davranması gerektiğine ilişkin ek belgeler vardır.
- Kod güncelleştirmelerinin getirdiği hatalar olan regresyonlar, otomatik derleme ve dağıtım sırasında bulunur.
Bu konu başlığında Sayfalar uygulamaları ve birim testleri hakkında Razor temel bilgilere sahip olduğunuz varsayılır. Sayfalar uygulamaları veya test kavramları hakkında Razor bilginiz yoksa aşağıdaki konulara bakın:
- ASP.NET Core'da Sayfalara Razor Giriş
- Öğretici: ASP.NET Core'da Razor Pages'i kullanmaya başlama
- Dotnet test ve xUnit kullanarak .NET Core'da C# birim testi
Örnek kodu görüntüleme veya indirme (indirme)
Örnek proje iki uygulamadan oluşur:
Uygulama | Proje klasörü | Açıklama |
---|---|---|
İleti uygulaması | src/RazorPagesTestSample | Kullanıcının ileti eklemesine, bir iletiyi silmesine, tüm iletileri silmesine ve iletileri analiz etmesine izin verir (ileti başına ortalama sözcük sayısını bulur). |
Test uygulaması | tests/RazorPagesTestSample.Tests | İleti uygulamasının DAL ve Dizin sayfası modelini birim testi için kullanılır. |
Testler, Visual Studio gibi bir IDE'nin yerleşik test özellikleri kullanılarak çalıştırılabilir. Visual Studio Code veya komut satırı kullanıyorsanız, tests/RazorPagesTestSample.Tests klasöründeki bir komut isteminde aşağıdaki komutu yürütür:
dotnet test
İleti uygulaması kuruluşu
İleti uygulaması, aşağıdaki özelliklere sahip bir Razor Sayfalar ileti sistemidir:
- Uygulamanın (
Pages/Index.cshtml
vePages/Index.cshtml.cs
) Dizin sayfası, iletilerin eklenmesini, silinmesini ve analizini denetlemek için bir kullanıcı arabirimi ve sayfa modeli yöntemleri sağlar (ileti başına ortalama sözcük sayısını bulur). - bir ileti sınıfı
Data/Message.cs
() tarafındanMessage
iki özelliğe sahip olarak açıklanır:Id
(anahtar) veText
(ileti).Text
özelliği gereklidir ve 200 karakterle sınırlıdır. - İletiler Entity Framework'ün bellek içi veritabanı† kullanılarak depolanır.
- Uygulama, veritabanı bağlam sınıfında
AppDbContext
Data/AppDbContext.cs
() bir DAL içerir. DAL yöntemleri, testlerde kullanılmak üzere yöntemlerin sahtesini oluşturmanızı sağlayan olarak işaretlenirvirtual
. - Uygulama başlangıcında veritabanı boşsa, ileti deposu üç iletiyle başlatılır. Bu dağıtılmış iletiler testlerde de kullanılır.
†InMemory ile Test et ef konusu, MSTest ile testler için bellek içi veritabanının nasıl kullanılacağını açıklar. Bu konu, xUnit test çerçevesini kullanır. Farklı test çerçevelerindeki test kavramları ve test uygulamaları benzerdir ancak aynı değildir.
Örnek uygulama depo desenini kullanmasa ve çalışma birimi (UoW) deseninin etkili bir örneği olmasa da, Razor Sayfalar bu geliştirme desenlerini destekler. Daha fazla bilgi için bkz . Altyapı kalıcılık katmanını tasarlama ve ASP.NET Core'da test denetleyicisi mantığı (örnek depo düzenini uygular).
Uygulama kuruluşunu test et
Test uygulaması tests/RazorPagesTestSample.Tests klasörünün içindeki bir konsol uygulamasıdır.
Test uygulaması klasörü | Açıklama |
---|---|
UnitTests |
|
Yardımcı program | Veritabanının TestDbContextOptions her test için temel koşuluna sıfırlanması için her DAL birim testi için yeni veritabanı bağlam seçenekleri oluşturmak için kullanılan yöntemi içerir. |
Test çerçevesi xUnit'tir. Nesne sahte çerçevesi Moq'tır.
Veri erişim katmanının birim testleri (DAL)
İleti uygulaması, sınıfında (src/RazorPagesTestSample/Data/AppDbContext.cs
) bulunan dört yöntem içeren bir DAL'a AppDbContext
sahiptir. Her yöntemin test uygulamasında bir veya iki birim testi vardır.
DAL yöntemi | İşlev |
---|---|
GetMessagesAsync |
özelliğine göre sıralanmış veritabanından Text bir List<Message> alır. |
AddMessageAsync |
Veritabanına bir Message ekler. |
DeleteAllMessagesAsync |
Veritabanındaki tüm Message girdileri siler. |
DeleteMessageAsync |
veritabanından tek Message bir öğesini tarafından Id siler. |
DAL'nin birim testleri, her test için yeni AppDbContext
bir oluşturma işlemini gerektirirDbContextOptions. Her test için oluşturma DbContextOptions
yaklaşımlarından biri kullanmaktır DbContextOptionsBuilder:
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb");
using (var db = new AppDbContext(optionsBuilder.Options))
{
// Use the db here in the unit test.
}
Bu yaklaşımdaki sorun, her testin veritabanını önceki testte bıraktığı durumda almasıdır. Bu, birbiriyle karışmadan atomik birim testleri yazmaya çalışırken sorun olabilir. öğesini her test için yeni bir veritabanı bağlamı kullanmaya zorlamak AppDbContext
için yeni bir hizmet sağlayıcısını temel alan bir DbContextOptions
örnek sağlayın. Test uygulaması, bunun sınıf yöntemini TestDbContextOptions
(tests/RazorPagesTestSample.Tests/Utilities/Utilities.cs
) kullanarak Utilities
nasıl yapılacağını gösterir:
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;
}
DAL birim testlerinde komutunun DbContextOptions
kullanılması, her testin yeni bir veritabanı örneğiyle atomik olarak çalışmasına olanak tanır:
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Use the db here in the unit test.
}
(UnitTests/DataAccessLayerTest.cs
) sınıfındaki DataAccessLayerTest
her test yöntemi benzer bir Arrange-Act-Assert desenini izler:
- Düzenleme: Veritabanı test için yapılandırılır ve/veya beklenen sonuç tanımlanır.
- Eylem: Test yürütülür.
- Onay: Test sonucunun başarılı olup olmadığını belirlemek için onaylar yapılır.
Örneğin yöntemi, DeleteMessageAsync
(src/RazorPagesTestSample/Data/AppDbContext.cs
) tarafından Id
tanımlanan tek bir iletiyi kaldırmakla sorumludur:
public async virtual Task DeleteMessageAsync(int id)
{
var message = await Messages.FindAsync(id);
if (message != null)
{
Messages.Remove(message);
await SaveChangesAsync();
}
}
Bu yöntem için iki test vardır. Bir test, ileti veritabanında mevcut olduğunda yöntemin bir iletiyi silip silmediğini denetler. Diğer yöntem, silme iletisi Id
yoksa veritabanının değişmediğini test eder. DeleteMessageAsync_MessageIsDeleted_WhenMessageIsFound
yöntemi aşağıda gösterilmiştir:
[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));
}
}
İlk olarak, yöntem Düzenleme adımını gerçekleştirir ve burada Act adımı için hazırlık gerçekleştirilir. Tohumlama iletileri alınır ve içinde seedMessages
tutulur. Tohumlama iletileri veritabanına kaydedilir. içeren ileti Id
1
silinmek üzere ayarlanmıştır. DeleteMessageAsync
yöntemi yürütülürken, beklenen iletilerde , ile olan dışında Id
1
tüm iletiler bulunmalıdır. değişkeni bu expectedMessages
beklenen sonucu temsil eder.
// Arrange
var seedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(seedMessages);
await db.SaveChangesAsync();
var recId = 1;
var expectedMessages =
seedMessages.Where(message => message.Id != recId).ToList();
yöntemi şu şekilde davranır: DeleteMessageAsync
yöntemi, öğesini geçirerek recId
1
yürütülür:
// Act
await db.DeleteMessageAsync(recId);
Son olarak, yöntemi bağlamdan öğesini alır Messages
ve ikisinin expectedMessages
eşit olduğunu onaylama işlemiyle karşılaştırır:
// 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));
İkisinin aynı olduğunu List<Message>
karşılaştırmak için:
- İletiler tarafından
Id
sıralanır. - İleti çiftleri özelliğinde
Text
karşılaştırılır.
Benzer bir test yöntemi, DeleteMessageAsync_NoMessageIsDeleted_WhenMessageIsNotFound
var olmayan bir iletiyi silme girişiminin sonucunu denetler. Bu durumda, yöntem yürütüldükten sonra veritabanında beklenen iletiler gerçek iletilere DeleteMessageAsync
eşit olmalıdır. Veritabanının içeriğinde değişiklik yapılmamalıdır:
[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));
}
}
Sayfa modeli yöntemlerinin birim testleri
Başka bir birim testi kümesi de sayfa modeli yöntemlerinin testlerinden sorumludur. İleti uygulamasında, Dizin sayfası modelleri sınıfında IndexModel
src/RazorPagesTestSample/Pages/Index.cshtml.cs
bulunur.
Sayfa modeli yöntemi | İşlev |
---|---|
OnGetAsync |
yöntemini kullanarak GetMessagesAsync kullanıcı arabirimi için DAL'den iletileri alır. |
OnPostAddMessageAsync |
ModelState geçerliyse, veritabanına ileti eklemek için çağrılarAddMessageAsync . |
OnPostDeleteAllMessagesAsync |
Veritabanındaki tüm iletileri silmek için çağrılar DeleteAllMessagesAsync . |
OnPostDeleteMessageAsync |
DeleteMessageAsync Belirtilen ile bir iletiyi silmek için yürütürId . |
OnPostAnalyzeMessagesAsync |
Veritabanında bir veya daha fazla ileti varsa, ileti başına ortalama sözcük sayısını hesaplar. |
Sayfa modeli yöntemleri(tests/RazorPagesTestSample.Tests/UnitTests/IndexPageTests.cs
sınıfında yedi test IndexPageTests
kullanılarak test edilir. Testler tanıdık Düzenleme-Assert-Act desenini kullanır. Bu testler şunlara odaklanır:
- ModelState geçersiz olduğunda yöntemlerin doğru davranışı izleyip izlemediğini belirleme.
- Yöntemlerin doğru şekilde üretildiğini IActionResultonaylama.
- Özellik değeri atamalarının doğru yapılarak denetleniyor.
Bu test grubu genellikle bir sayfa modeli yönteminin yürütüldüğü Act adımı için beklenen verileri üretmek üzere DAL yöntemleriyle dalga geçer. Örneğin, GetMessagesAsync
yöntemi AppDbContext
çıkış üretmek için sahtedir. Bir sayfa modeli yöntemi bu yöntemi yürüttüğünde, sahte sonuç döndürür. Veriler veritabanından gelmez. Bu, DAL'yi sayfa modeli testlerinde kullanmak için öngörülebilir, güvenilir test koşulları oluşturur.
Test, OnGetAsync_PopulatesThePageModel_WithAListOfMessages
yöntemin GetMessagesAsync
sayfa modeli için nasıl sahte olduğunu gösterir:
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
Yöntem Act adımında yürütülürken sayfa modelinin GetMessagesAsync
yöntemini çağırır.
Birim testi Yasası adımı (tests/RazorPagesTestSample.Tests/UnitTests/IndexPageTests.cs
):
// Act
await pageModel.OnGetAsync();
IndexPage
sayfa modelinin OnGetAsync
yöntemi (src/RazorPagesTestSample/Pages/Index.cshtml.cs
):
public async Task OnGetAsync()
{
Messages = await _db.GetMessagesAsync();
}
GetMessagesAsync
DAL içindeki yöntemi, bu yöntem çağrısının sonucunu döndürmez. Yöntemin sahte sürümü sonucu döndürür.
Assert
Adımda, gerçek iletiler (actualMessages
) sayfa modelinin Messages
özelliğinden atanır. İletiler atandığında bir tür denetimi de gerçekleştirilir. Beklenen ve gerçek iletiler özellikleriyle Text
karşılaştırılır. Test, iki List<Message>
örneğin aynı iletileri içerdiğini onaylar.
// 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));
Bu gruptaki diğer testler, , ActionContext ModelStateDictionaryViewDataDictionary
bir ve PageContext
oluşturmak için PageContext
, , içeren sayfa modeli nesneleri DefaultHttpContextoluşturur. Bunlar, testlerin yürütülmesinde yararlıdır. Örneğin, ileti uygulaması yürütülürken OnPostAddMessageAsync
geçerli PageResult bir döndürüldüğünü denetlemek için ile AddModelError bir ModelState
hata oluşturur:
[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);
}
Ek kaynaklar
- Dotnet test ve xUnit kullanarak .NET Core'da C# birim testi
- ASP.NET Core'da test denetleyicisi mantığı
- Kodunuzu Birim Testi (Visual Studio)
- ASP.NET Core'da tümleştirme testleri
- xUnit.net
- xUnit.net kullanmaya başlama: .NET SDK komut satırıyla .NET Core kullanma
- Moq
- Moq Hızlı Başlangıç
- JustMockLite: .NET geliştiricileri için sahte bir çerçeve. (Microsoft tarafından korunmaz veya desteklenmez.)
ASP.NET Core