ASP.NET Core'da tümleştirme testleri
Jos van der Til, Martin Costello ve Javier Calvarro Nelson tarafından.
Tümleştirme testleri, bir uygulamanın bileşenlerinin veritabanı, dosya sistemi ve ağ gibi uygulamanın destekleyici altyapısını içeren bir düzeyde düzgün çalışmasını sağlar. ASP.NET Core, test web konağı ve bellek içi test sunucusu ile birim test çerçevesi kullanarak tümleştirme testlerini destekler.
Bu makalede, birim testleri hakkında temel bilgiler olduğu varsayılır. Test kavramlarını bilmiyorsanız .NET Core ve .NET Standard'da Birim Testi makalesine ve bağlantılı içeriğine bakın.
Örnek kodu görüntüleme veya indirme (indirme)
Örnek uygulama bir Razor Sayfalar uygulamasıdır ve Sayfalar hakkında temel bir anlayış olduğunu Razor varsayar. Pages'ı tanımıyorsanız Razor aşağıdaki makalelere bakın:
SPA'ları test etme amacıyla tarayıcıyı otomatikleştirebilen .NET için Playwright gibi bir araç öneririz.
Tümleştirme testlerine giriş
Tümleştirme testleri, bir uygulamanın bileşenlerini birim testlerinden daha geniş bir düzeyde değerlendirir. Birim testleri, tek tek sınıf yöntemleri gibi yalıtılmış yazılım bileşenlerini test etmek için kullanılır. Tümleştirme testleri, iki veya daha fazla uygulama bileşeninin birlikte çalışarak beklenen bir sonuç elde ettiğini ve büyük olasılıkla bir isteği tam olarak işlemek için gereken her bileşenin de dahil olduğunu onaylar.
Bu daha geniş testler, genellikle aşağıdaki bileşenler de dahil olmak üzere uygulamanın altyapısını ve tüm çerçevesini test etmek için kullanılır:
- Veritabanı
- Dosya sistemi
- Ağ gereçleri
- İstek-yanıt işlem hattı
Birim testleri, altyapı bileşenleri yerine sahte veya sahte nesneler olarak bilinen fabrikatlanmış bileşenleri kullanır.
Birim testlerinin aksine tümleştirme testleri:
- Uygulamanın üretimde kullandığı gerçek bileşenleri kullanın.
- Daha fazla kod ve veri işleme gerektirir.
- Çalıştırılması daha uzun sürer.
Bu nedenle, tümleştirme testlerinin kullanımını en önemli altyapı senaryolarıyla sınırlayın. Bir davranış birim testi veya tümleştirme testi kullanılarak test edilebiliyorsa birim testini seçin.
Tümleştirme testlerinin tartışmalarında, test edilen projeye genellikle Test Altındaki Sistem veya kısaca "SUT" adı verilir. "SUT" bu makalede test edilen ASP.NET Core uygulamasına başvurmak için kullanılır.
Veritabanları ve dosya sistemleriyle verilerin ve dosya erişiminin her permütasyonu için tümleştirme testleri yazmayın. Bir uygulama genelinde veritabanları ve dosya sistemleriyle kaç yerde etkileşim kurduğundan bağımsız olarak, odaklanmış bir dizi okuma, yazma, güncelleştirme ve silme tümleştirme testi genellikle veritabanı ve dosya sistemi bileşenlerini yeterince test edebilmektedir. Bu bileşenlerle etkileşim kuran yöntem mantığının rutin testleri için birim testlerini kullanın. Birim testlerinde, altyapı sahteleri veya sahteleri kullanımı test yürütmenin daha hızlı gerçekleşmesine neden olur.
ASP.NET Core tümleştirme testleri
ASP.NET Core'daki tümleştirme testleri aşağıdakileri gerektirir:
- Testleri içermek ve yürütmek için bir test projesi kullanılır. Test projesinin SUT başvurusu vardır.
- Test projesi SUT için bir test web konağı oluşturur ve SUT ile istekleri ve yanıtları işlemek için bir test sunucusu istemcisi kullanır.
- Testleri yürütmek ve test sonuçlarını raporlamak için bir test çalıştırıcısı kullanılır.
Tümleştirme testleri, her zamanki Düzenleme, Eylem ve Onay testi adımlarını içeren bir dizi olayı izler:
- SUT'nin web konağı yapılandırıldı.
- Uygulamaya istek göndermek için bir test sunucusu istemcisi oluşturulur.
- Test düzenleme adımı yürütülür: Test uygulaması bir istek hazırlar.
- Eylem test adımı yürütülür: İstemci isteği gönderir ve yanıtı alır.
- Assert test adımı yürütülür: Gerçek yanıt, beklenen yanıta göre geçiş veya başarısız olarak doğrulanır.
- Tüm testler yürütülene kadar işlem devam eder.
- Test sonuçları bildirilir.
Genellikle test web konağı, test çalıştırmaları için uygulamanın normal web ana bilgisayarından farklı yapılandırılır. Örneğin, testler için farklı bir veritabanı veya farklı uygulama ayarları kullanılabilir.
Test web konağı ve bellek içi test sunucusu ()TestServer gibi altyapı bileşenleri Microsoft.AspNetCore.Mvc.Testing paketi tarafından sağlanır veya yönetilir. Bu paketin kullanımı test oluşturma ve yürütmeyi kolaylaştırır.
Paket Microsoft.AspNetCore.Mvc.Testing
aşağıdaki görevleri işler:
- Bağımlılık dosyasını (
.deps
) SUT'den test projesininbin
dizinine kopyalar. - testler yürütürken statik dosyaların ve sayfaların/görünümlerin bulunması için içerik kökünü SUT'nin proje köküne ayarlar.
- ile
TestServer
SUT önyüklemesini kolaylaştırmak için WebApplicationFactory sınıfını sağlar.
Birim testleri belgelerinde bir test projesi ve test çalıştırıcısının nasıl ayarlanacağı ve testleri çalıştırma hakkında ayrıntılı yönergelerin yanı sıra testleri ve test sınıflarını adlandırmaya yönelik öneriler açıklanmaktadır.
Birim testlerini tümleştirme testlerinden farklı projelere ayırın. Testleri ayırma:
- Altyapı testi bileşenlerinin birim testlerine yanlışlıkla dahil edilmesini sağlamaya yardımcı olur.
- Hangi test kümesinin çalıştırıldığı üzerinde denetime izin verir.
Sayfalar uygulamalarının ve MVC uygulamalarının testlerinin Razor yapılandırması arasında neredeyse hiçbir fark yoktur. Tek fark, testlerin nasıl adlandırıldığındandır. Razor Sayfalar uygulamasında, sayfa uç noktalarının testleri genellikle sayfa modeli sınıfından (örneğin, IndexPageTests
Dizin sayfası için bileşen tümleştirmesini test etmek için) adlandırılır. MVC uygulamasında testler genellikle denetleyici sınıflarına göre düzenlenir ve test ettikleri denetleyicilerden (örneğin, HomeControllerTests
denetleyici için bileşen tümleştirmesini Home test etmek için) adlandırılır.
Uygulama önkoşullarını test edin
Test projesinin aşağıdakileri yapması gerekir:
Microsoft.AspNetCore.Mvc.Testing
paketine başvurun.- Proje dosyasında (
<Project Sdk="Microsoft.NET.Sdk.Web">
) Web SDK'sını belirtin.
Bu önkoşullar örnek uygulamada görülebilir. tests/RazorPagesProject.Tests/RazorPagesProject.Tests.csproj
Dosyayı inceleyin. Örnek uygulama xUnit test çerçevesini ve AngleSharp ayrıştırıcı kitaplığını kullandığından örnek uygulama da aşağıdakilere başvurur:
Sürüm 2.4.2 veya üzerini kullanan xunit.runner.visualstudio
uygulamalarda test projesinin pakete başvurması Microsoft.NET.Test.Sdk
gerekir.
Entity Framework Core, testlerde de kullanılır. GitHub'daki proje dosyasına bakın.
SUT ortamı
SUT'nin ortamı ayarlı değilse, ortam varsayılan olarak Geliştirme olarak ayarlanır.
Varsayılan WebApplicationFactory ile temel testler
Aşağıdakilerden birini yaparak örtük olarak tanımlanmış Program
sınıfı test projesinde kullanıma sunma:
Web uygulamasından test projesine iç türleri kullanıma sunma. Bu işlem SUT projesinin dosyasında (
.csproj
):<ItemGroup> <InternalsVisibleTo Include="MyTestProject" /> </ItemGroup>
Program
Kısmi bir sınıf bildirimi kullanarak sınıfını genel yapın:var builder = WebApplication.CreateBuilder(args); // ... Configure services, routes, etc. app.Run(); + public partial class Program { }
Örnek uygulama kısmi sınıf yaklaşımını
Program
kullanır.
WebApplicationFactory<TEntryPoint> tümleştirme testlerine yönelik bir TestServer oluşturmak için kullanılır. TEntryPoint
genellikle Program.cs
SUT'nin giriş noktası sınıfıdır.
Test sınıfları, sınıfın testleri içerdiğini belirtmek ve sınıftaki testler arasında paylaşılan nesne örnekleri sağlamak için bir sınıf fikstür arabirimi (IClassFixture
) uygular.
Aşağıdaki test sınıfı, BasicTests
SUT'yi önyüklemek ve bir test yöntemi Get_EndpointsReturnSuccessAndCorrectContentType
sağlamak HttpClient için öğesini kullanırWebApplicationFactory
. yöntemi, yanıt durum kodunun başarılı olduğunu (200-299) ve Content-Type
üst bilgi de birkaç uygulama sayfası için doğrular text/html; charset=utf-8
.
CreateClient() otomatik olarak yeniden yönlendirmeleri izleyen ve tanımlama bilgilerini işleyen bir örneği HttpClient
oluşturur.
public class BasicTests
: IClassFixture<WebApplicationFactory<Program>>
{
private readonly WebApplicationFactory<Program> _factory;
public BasicTests(WebApplicationFactory<Program> factory)
{
_factory = factory;
}
[Theory]
[InlineData("/")]
[InlineData("/Index")]
[InlineData("/About")]
[InlineData("/Privacy")]
[InlineData("/Contact")]
public async Task Get_EndpointsReturnSuccessAndCorrectContentType(string url)
{
// Arrange
var client = _factory.CreateClient();
// Act
var response = await client.GetAsync(url);
// Assert
response.EnsureSuccessStatusCode(); // Status Code 200-299
Assert.Equal("text/html; charset=utf-8",
response.Content.Headers.ContentType.ToString());
}
}
Varsayılan olarak, Genel Veri Koruma Yönetmeliği onay ilkesi etkinleştirildiğinde gerekli olmayan tanımlama bilgileri istekler arasında korunmaz. TempData sağlayıcısı tarafından kullanılanlar gibi temel olmayan tanımlama bilgilerini korumak için bunları testlerinizde temel olarak işaretleyin. Temel olarak işaretleme cookie yönergeleri için bkz . Temel tanımlama bilgileri.
AngleSharp ile Application Parts
antiforgery denetimleri karşılaştırması
Bu makalede, sayfaları yükleyerek ve HTML ayrıştırarak antiforgery denetimlerini işlemek için AngleSharp ayrıştırıcısı kullanılır. Denetleyici ve Razor Sayfalar görünümlerinin uç noktalarını tarayıcıda nasıl işlediklerine önem vermeden daha düşük bir düzeyde test için kullanmayı Application Parts
göz önünde bulundurun. Uygulama Bölümleri yaklaşımı, uygulamaya gerekli değerleri almak için JSON isteklerinde bulunmak için kullanılabilecek bir denetleyici veya Razor Sayfa ekler. Daha fazla bilgi için Bkz. Tümleştirme Testi ASP.NET Uygulama Bölümlerini Kullanarak Sahtekarlık Önleme ile Korunan Temel Kaynaklar ve Martin Costello tarafından ilişkili GitHub deposu.
WebApplicationFactory'i özelleştirme
Web ana bilgisayar yapılandırması, bir veya daha fazla özel fabrika oluşturmak için öğesinden devralınarak test sınıflarından WebApplicationFactory<TEntryPoint> bağımsız olarak oluşturulabilir:
öğesinden
WebApplicationFactory
devralın ve öğesini geçersiz kılın ConfigureWebHost. ile IWebHostBuilder hizmet koleksiyonunun yapılandırılmasına izin verirIWebHostBuilder.ConfigureServices
public class CustomWebApplicationFactory<TProgram> : WebApplicationFactory<TProgram> where TProgram : class { protected override void ConfigureWebHost(IWebHostBuilder builder) { builder.ConfigureServices(services => { var dbContextDescriptor = services.SingleOrDefault( d => d.ServiceType == typeof(DbContextOptions<ApplicationDbContext>)); services.Remove(dbContextDescriptor); var dbConnectionDescriptor = services.SingleOrDefault( d => d.ServiceType == typeof(DbConnection)); services.Remove(dbConnectionDescriptor); // Create open SqliteConnection so EF won't automatically close it. services.AddSingleton<DbConnection>(container => { var connection = new SqliteConnection("DataSource=:memory:"); connection.Open(); return connection; }); services.AddDbContext<ApplicationDbContext>((container, options) => { var connection = container.GetRequiredService<DbConnection>(); options.UseSqlite(connection); }); }); builder.UseEnvironment("Development"); } }
Örnek uygulamadaki veritabanı tohumlama yöntemi tarafından
InitializeDbForTests
gerçekleştirilir. Yöntemi, Tümleştirme testleri örneği: Test uygulaması kuruluşu bölümünde açıklanmıştır.SUT'nin veritabanı bağlamı içinde
Program.cs
kaydedilir. Test uygulamasınınbuilder.ConfigureServices
geri çağırması, uygulamanınProgram.cs
kodu yürütüldükten sonra yürütülür. Testlerde uygulamanın veritabanından farklı bir veritabanı kullanmak için, uygulamanın veritabanı bağlamı içindebuilder.ConfigureServices
değiştirilmelidir.Örnek uygulama, veritabanı bağlamı için hizmet tanımlayıcısını bulur ve hizmet kaydını kaldırmak için tanımlayıcıyı kullanır. Ardından fabrika, testler için bellek içi veritabanı kullanan yeni
ApplicationDbContext
bir ekliyor..Farklı bir veritabanına bağlanmak için öğesini
DbConnection
değiştirin. SQL Server test veritabanını kullanmak için:- Proje dosyasındaKi
Microsoft.EntityFrameworkCore.SqlServer
NuGet paketine başvurun. UseInMemoryDatabase
çağrısı yapın.
- Proje dosyasındaKi
Test sınıflarında özel
CustomWebApplicationFactory
öğesini kullanın. Aşağıdaki örnekte sınıfındakiIndexPageTests
fabrika kullanılır:public class IndexPageTests : IClassFixture<CustomWebApplicationFactory<Program>> { private readonly HttpClient _client; private readonly CustomWebApplicationFactory<Program> _factory; public IndexPageTests( CustomWebApplicationFactory<Program> factory) { _factory = factory; _client = factory.CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false }); }
Örnek uygulamanın istemcisi, aşağıdaki yeniden yönlendirmelerin
HttpClient
engellenmesi için yapılandırılır. Sahte kimlik doğrulaması bölümünde daha sonra açıklandığı gibi bu, testlerin uygulamanın ilk yanıtının sonucunu denetlemesine izin verir. İlk yanıt, bu testlerin çoğunda üst bilgi içeren birLocation
yeniden yönlendirmedir.Tipik bir test, isteği ve yanıtı işlemek için ve yardımcı yöntemlerini kullanır
HttpClient
:[Fact] public async Task Post_DeleteAllMessagesHandler_ReturnsRedirectToRoot() { // Arrange var defaultPage = await _client.GetAsync("/"); var content = await HtmlHelpers.GetDocumentAsync(defaultPage); //Act var response = await _client.SendAsync( (IHtmlFormElement)content.QuerySelector("form[id='messages']"), (IHtmlButtonElement)content.QuerySelector("button[id='deleteAllBtn']")); // Assert Assert.Equal(HttpStatusCode.OK, defaultPage.StatusCode); Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); Assert.Equal("/", response.Headers.Location.OriginalString); }
SUT'ye yapılan herhangi bir POST isteği, uygulamanın veri koruma önleme sistemi tarafından otomatik olarak yapılan kötü amaçlı yazılımdan koruma denetimini karşılamalıdır. Testin POST isteğini düzenlemek için test uygulamasının şunları yapması gerekir:
- Sayfa için bir istekte bulun.
- Antiforgery'yi cookie ayrıştırın ve yanıttan doğrulama belirteci isteyin.
- POST isteğini sahteciliğe cookie karşı koruma ve istek doğrulama belirteci ile gerçekleştirin.
Örnek SendAsync
uygulamadaki GetDocumentAsync
yardımcı uzantı yöntemleri (Helpers/HttpClientExtensions.cs
) ve yardımcı yöntemi (Helpers/HtmlHelpers.cs
), aşağıdaki yöntemlerle antiforgery denetimini işlemek için AngleSharp ayrıştırıcısını kullanır:
GetDocumentAsync
: alır HttpResponseMessage ve döndürürIHtmlDocument
.GetDocumentAsync
, özgünHttpResponseMessage
öğesini temel alan bir sanal yanıt hazırlayan bir fabrika kullanır. Daha fazla bilgi için AngleSharp belgelerine bakın.SendAsync
oluşturma HttpRequestMessage ve SUT'ye istek gönderme çağrısı SendAsync(HttpRequestMessage) için uzantı yöntemleriHttpClient
. HTML formunu (IHtmlFormElement
) ve aşağıdakileri kabul etmek içinSendAsync
aşırı yüklemeler:- Formun Gönder düğmesi (
IHtmlElement
) - Form değerleri koleksiyonu (
IEnumerable<KeyValuePair<string, string>>
) - Gönder düğmesi (
IHtmlElement
) ve form değerleri (IEnumerable<KeyValuePair<string, string>>
)
- Formun Gönder düğmesi (
AngleSharp, bu makalede ve örnek uygulamada gösterim amacıyla kullanılan bir üçüncü taraf ayrıştırma kitaplığıdır. AngleSharp, ASP.NET Core uygulamalarının tümleştirme testi için desteklenmez veya gerekli değildir. Html Çeviklik Paketi (HAP) gibi diğer ayrıştırıcılar kullanılabilir. Bir diğer yaklaşım da, sahteciliğe karşı koruma sisteminin istek doğrulama belirtecini ve kötü amaçlı yazılımdan korumayı doğrudan işlemek için kod yazmaktır cookie . Daha fazla bilgi için bu makaledeki AngleSharp vs Application Parts
antiforgery denetimleri konusuna bakın.
EF-Core bellek içi veritabanı sağlayıcısı sınırlı ve temel test için kullanılabilir, ancak bellek içi test için önerilen seçenek SQLite sağlayıcısıdır.
Bkz . Başlangıç'ı başlangıç filtreleri ile genişletme. Bu, bir test özel hizmet veya ara yazılım gerektirdiğinde yararlı olan kullanarak IStartupFilterara yazılımı yapılandırmayı gösterir.
WithWebHostBuilder ile istemciyi özelleştirme
Bir test yönteminde ek yapılandırma gerektiğinde, WithWebHostBuilder yapılandırma tarafından daha da özelleştirilmiş bir ile yeni WebApplicationFactory
bir IWebHostBuilder oluşturur.
Örnek kod, yapılandırılmış hizmetleri test saptamalarıyla değiştirmek için çağırırWithWebHostBuilder
. Daha fazla bilgi ve örnek kullanım için bu makaledeki Sahte hizmetler ekleme bölümüne bakın.
Post_DeleteMessageHandler_ReturnsRedirectToRoot
Örnek uygulamanın test yöntemi, kullanımını WithWebHostBuilder
gösterir. Bu test, SUT'da form gönderimini tetikleyerek veritabanında bir kayıt silme işlemi gerçekleştirir.
sınıfındaki IndexPageTests
başka bir test veritabanındaki tüm kayıtları silen ve yönteminden önce Post_DeleteMessageHandler_ReturnsRedirectToRoot
çalıştırabilen bir işlem gerçekleştirdiğinden, SUT'nin silmesi için bir kaydın mevcut olduğundan emin olmak için bu test yönteminde veritabanı yeniden görüntülenir. SUT'daki formun ilk sil düğmesinin messages
seçilmesi, SUT isteğinde benzetim yapılır:
[Fact]
public async Task Post_DeleteMessageHandler_ReturnsRedirectToRoot()
{
// Arrange
using (var scope = _factory.Services.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<ApplicationDbContext>();
Utilities.ReinitializeDbForTests(db);
}
var defaultPage = await _client.GetAsync("/");
var content = await HtmlHelpers.GetDocumentAsync(defaultPage);
//Act
var response = await _client.SendAsync(
(IHtmlFormElement)content.QuerySelector("form[id='messages']"),
(IHtmlButtonElement)content.QuerySelector("form[id='messages']")
.QuerySelector("div[class='panel-body']")
.QuerySelector("button"));
// Assert
Assert.Equal(HttpStatusCode.OK, defaultPage.StatusCode);
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
Assert.Equal("/", response.Headers.Location.OriginalString);
}
İstemci seçenekleri
WebApplicationFactoryClientOptions Örnek oluştururken HttpClient
varsayılanlar ve kullanılabilir seçenekler için sayfaya bakın.
sınıfını WebApplicationFactoryClientOptions
oluşturun ve yöntemine CreateClient() geçirin:
public class IndexPageTests :
IClassFixture<CustomWebApplicationFactory<Program>>
{
private readonly HttpClient _client;
private readonly CustomWebApplicationFactory<Program>
_factory;
public IndexPageTests(
CustomWebApplicationFactory<Program> factory)
{
_factory = factory;
_client = factory.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
}
NOT: HTTPS Yeniden Yönlendirme Ara Yazılımı kullanılırken günlüklerde HTTPS yeniden yönlendirme uyarılarından kaçınmak için BaseAddress = new Uri("https://localhost")
Sahte hizmetler ekleme
Hizmetler, konak oluşturucusunda çağrısı ConfigureTestServices yapılan bir testte geçersiz kılınabilir. Geçersiz kılınan hizmetlerin kapsamını testin kendisi olarak tanımlamak için yöntemi bir WithWebHostBuilder konak oluşturucu almak için kullanılır. Bu durum aşağıdaki testlerde görülebilir:
- Get_QuoteService_ProvidesQuoteInPage
- Get_GithubProfilePageCanGetAGithubUser
- Get_SecurePageIsReturnedForAnAuthenticatedUser
Örnek SUT, teklif döndüren kapsamlı bir hizmet içerir. Teklif, Dizin sayfası istendiğinde Dizin sayfasındaki gizli bir alana eklenir.
Services/IQuoteService.cs
:
public interface IQuoteService
{
Task<string> GenerateQuote();
}
Services/QuoteService.cs
:
// Quote ©1975 BBC: The Doctor (Tom Baker); Dr. Who: Planet of Evil
// https://www.bbc.co.uk/programmes/p00pyrx6
public class QuoteService : IQuoteService
{
public Task<string> GenerateQuote()
{
return Task.FromResult<string>(
"Come on, Sarah. We've an appointment in London, " +
"and we're already 30,000 years late.");
}
}
Program.cs
:
services.AddScoped<IQuoteService, QuoteService>();
Pages/Index.cshtml.cs
:
public class IndexModel : PageModel
{
private readonly ApplicationDbContext _db;
private readonly IQuoteService _quoteService;
public IndexModel(ApplicationDbContext db, IQuoteService quoteService)
{
_db = db;
_quoteService = quoteService;
}
[BindProperty]
public Message Message { get; set; }
public IList<Message> Messages { get; private set; }
[TempData]
public string MessageAnalysisResult { get; set; }
public string Quote { get; private set; }
public async Task OnGetAsync()
{
Messages = await _db.GetMessagesAsync();
Quote = await _quoteService.GenerateQuote();
}
Pages/Index.cs
:
<input id="quote" type="hidden" value="@Model.Quote">
SUT uygulaması çalıştırıldığında aşağıdaki işaretleme oluşturulur:
<input id="quote" type="hidden" value="Come on, Sarah. We've an appointment in
London, and we're already 30,000 years late.">
Tümleştirme testinde hizmeti ve teklif eklemeyi test etmek için test tarafından SUT'ye sahte hizmet eklenir. Sahte hizmet, uygulamanın yerine test uygulaması QuoteService
tarafından sağlanan ve adlı TestQuoteService
bir hizmettir:
IntegrationTests.IndexPageTests.cs
:
// Quote ©1975 BBC: The Doctor (Tom Baker); Pyramids of Mars
// https://www.bbc.co.uk/programmes/p00pys55
public class TestQuoteService : IQuoteService
{
public Task<string> GenerateQuote()
{
return Task.FromResult(
"Something's interfering with time, Mr. Scarman, " +
"and time is my business.");
}
}
ConfigureTestServices
çağrılır ve kapsamı belirlenmiş hizmet kaydedilir:
[Fact]
public async Task Get_QuoteService_ProvidesQuoteInPage()
{
// Arrange
var client = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.AddScoped<IQuoteService, TestQuoteService>();
});
})
.CreateClient();
//Act
var defaultPage = await client.GetAsync("/");
var content = await HtmlHelpers.GetDocumentAsync(defaultPage);
var quoteElement = content.QuerySelector("#quote");
// Assert
Assert.Equal("Something's interfering with time, Mr. Scarman, " +
"and time is my business.", quoteElement.Attributes["value"].Value);
}
Testin yürütülmesi sırasında oluşturulan işaretleme, tarafından TestQuoteService
sağlanan tırnak metnini yansıtır, böylece onay geçer:
<input id="quote" type="hidden" value="Something's interfering with time,
Mr. Scarman, and time is my business.">
Sahte kimlik doğrulaması
Sınıfındaki AuthTests
testler güvenli bir uç nokta olup olmadığını denetler:
- Kimliği doğrulanmamış bir kullanıcıyı uygulamanın oturum açma sayfasına yönlendirir.
- Kimliği doğrulanmış bir kullanıcının içeriğini döndürür.
SUT'de sayfa, /SecurePage
sayfaya uygulamak için bir AuthorizePage AuthorizeFilter kural kullanır. Daha fazla bilgi için bkz Razor . Sayfa yetkilendirme kuralları.
services.AddRazorPages(options =>
{
options.Conventions.AuthorizePage("/SecurePage");
});
Testte Get_SecurePageRedirectsAnUnauthenticatedUser
, ayarı WebApplicationFactoryClientOptions olarak ayarlanarak AllowAutoRedirect yeniden yönlendirmelere izin vermemeye false
ayarlanmıştır:
[Fact]
public async Task Get_SecurePageRedirectsAnUnauthenticatedUser()
{
// Arrange
var client = _factory.CreateClient(
new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
// Act
var response = await client.GetAsync("/SecurePage");
// Assert
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
Assert.StartsWith("http://localhost/Identity/Account/Login",
response.Headers.Location.OriginalString);
}
İstemcinin yeniden yönlendirmeyi izlemesine izin vermeyerek aşağıdaki denetimler yapılabilir:
- SUT tarafından döndürülen durum kodu, oturum açma sayfasına yeniden yönlendirmeden sonraki son durum koduna değil beklenen HttpStatusCode.Redirect sonucta göre denetlenebilir. Bu, olacaktır HttpStatusCode.OK.
- Yanıt
Location
üst bilgilerindeki üst bilgi değeri, üst bilginin bulunmayacağı son oturum açma sayfası yanıtıyla değil ileLocation
başladığınıhttp://localhost/Identity/Account/Login
onaylamak için denetlendi.
Test uygulaması, kimlik doğrulaması ve yetkilendirme özelliklerini test etmek için bir AuthenticationHandler<TOptions> ConfigureTestServices ile dalga geçebilir. En düşük senaryo bir AuthenticateResult.Successdöndürür:
public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public TestAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, UrlEncoder encoder)
: base(options, logger, encoder)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var claims = new[] { new Claim(ClaimTypes.Name, "Test user") };
var identity = new ClaimsIdentity(claims, "Test");
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, "TestScheme");
var result = AuthenticateResult.Success(ticket);
return Task.FromResult(result);
}
}
TestAuthHandler
, kimlik doğrulama düzeni için kaydedildiği yere AddAuthentication
ayarlandığında TestScheme
kullanıcının kimliğini doğrulamak için ConfigureTestServices
çağrılır. Düzenin uygulamanızın TestScheme
beklediği düzenle eşleşmesi önemlidir. Aksi takdirde kimlik doğrulaması çalışmaz.
[Fact]
public async Task Get_SecurePageIsReturnedForAnAuthenticatedUser()
{
// Arrange
var client = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.AddAuthentication(defaultScheme: "TestScheme")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(
"TestScheme", options => { });
});
})
.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false,
});
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(scheme: "TestScheme");
//Act
var response = await client.GetAsync("/SecurePage");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
hakkında WebApplicationFactoryClientOptions
daha fazla bilgi için İstemci seçenekleri bölümüne bakın.
Kimlik doğrulaması ara yazılımı için temel testler
Kimlik doğrulama ara yazılımının temel testleri için bu GitHub deposuna bakın. Test senaryosuna özgü bir test sunucusu içerir.
Ortamı ayarlama
Ortamı özel uygulama fabrikasında ayarlayın:
public class CustomWebApplicationFactory<TProgram>
: WebApplicationFactory<TProgram> where TProgram : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
var dbContextDescriptor = services.SingleOrDefault(
d => d.ServiceType ==
typeof(DbContextOptions<ApplicationDbContext>));
services.Remove(dbContextDescriptor);
var dbConnectionDescriptor = services.SingleOrDefault(
d => d.ServiceType ==
typeof(DbConnection));
services.Remove(dbConnectionDescriptor);
// Create open SqliteConnection so EF won't automatically close it.
services.AddSingleton<DbConnection>(container =>
{
var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
return connection;
});
services.AddDbContext<ApplicationDbContext>((container, options) =>
{
var connection = container.GetRequiredService<DbConnection>();
options.UseSqlite(connection);
});
});
builder.UseEnvironment("Development");
}
}
Test altyapısı uygulama içeriği kök yolunu nasıl çıkarsar?
Oluşturucu, WebApplicationFactory
derlemeye eşit TEntryPoint
bir WebApplicationFactoryContentRootAttribute anahtara sahip tümleştirme testlerini içeren derlemede öğesini arayarak uygulama içeriği kök yolunu çıkarsarSystem.Reflection.Assembly.FullName
. Doğru anahtara sahip bir özniteliğin bulunamazsa, WebApplicationFactory
çözüm dosyasını aramaya (.sln) geri döner ve derleme adını çözüm dizinine ekler TEntryPoint
. Uygulama kök dizini (içerik kök yolu), görünümleri ve içerik dosyalarını bulmak için kullanılır.
Gölge kopyalamayı devre dışı bırakma
Gölge kopyalama, testlerin çıkış dizininden farklı bir dizinde yürütülmesine neden olur. Testleriniz ile ilgili Assembly.Location
dosyaları yüklemeye bağlıysa ve sorunlarla karşılaşıyorsanız, gölge kopyalamayı devre dışı bırakmanız gerekebilir.
xUnit kullanırken gölge kopyalamayı devre dışı bırakmak için test projesi dizininizde doğru yapılandırma ayarıyla bir xunit.runner.json
dosya oluşturun:
{
"shadowCopy": false
}
Nesnelerin atılması
Uygulamanın testleri IClassFixture
yürütüldükten TestServer ve HttpClient xUnit WebApplicationFactory
tarafından atıldığında atılır. Geliştirici tarafından örneği oluşturulmuş nesneler elden çıkarılma gerektiriyorsa, bunları IClassFixture
uygulamada atın. Daha fazla bilgi için bkz . Dispose yöntemi uygulama.
Tümleştirme testleri örneği
Örnek uygulama iki uygulamadan oluşur:
Uygulama | Proje dizini | Açıklama |
---|---|---|
İleti uygulaması (SUT) | src/RazorPagesProject |
Kullanıcının bir ileti eklemesine, silmesine, tümünü silmesine ve iletileri analiz etmesine izin verir. |
Test uygulaması | tests/RazorPagesProject.Tests |
SUT'yi tümleştirme 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, dizindeki bir komut isteminde aşağıdaki komutu yürütürtests/RazorPagesProject.Tests
:
dotnet test
İleti uygulaması (SUT) kuruluşu
SUT, 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 (ileti başına ortalama sözcükler) denetlemek için bir kullanıcı arabirimi ve sayfa modeli yöntemleri sağlar. - 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
() bir veri erişim katmanı (Data/AppDbContext.cs
DAL) içerir. - Uygulama başlangıcında veritabanı boşsa, ileti deposu üç iletiyle başlatılır.
- Uygulama yalnızca kimliği doğrulanmış bir
/SecurePage
kullanıcı tarafından erişilebilen bir içerir.
† InMemory ile test etme ef makalesi, 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.
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 Test denetleyicisi mantığı (örnek, depo düzenini uygular).
Uygulama kuruluşunu test et
Test uygulaması, dizinin içindeki tests/RazorPagesProject.Tests
bir konsol uygulamasıdır.
Uygulama dizinini test et | Açıklama |
---|---|
AuthTests |
Aşağıdakiler için test yöntemlerini içerir:
|
BasicTests |
Yönlendirme ve içerik türü için bir test yöntemi içerir. |
IntegrationTests |
Özel WebApplicationFactory sınıf kullanarak Dizin sayfasının tümleştirme testlerini içerir. |
Helpers/Utilities |
|
Test çerçevesi xUnit'tir. Tümleştirme testleri, öğesini içeren TestServerkullanılarak Microsoft.AspNetCore.TestHostyapılır. Microsoft.AspNetCore.Mvc.Testing
Paket test ana bilgisayarını ve test sunucusunu yapılandırmak için kullanıldığından TestHost
ve TestServer
paketleri, test uygulamasının proje dosyasında veya test uygulamasındaki geliştirici yapılandırmasında doğrudan paket başvuruları gerektirmez.
Tümleştirme testleri genellikle test yürütmeden önce veritabanında küçük bir veri kümesi gerektirir. Örneğin, silme testi veritabanı kaydı silme işlemini çağırır, bu nedenle silme isteğinin başarılı olması için veritabanında en az bir kayıt olmalıdır.
Örnek uygulama, testleri yürütürken kullanabileceği üç iletiyle Utilities.cs
veritabanının çekirdeğini oluşturur:
public static void InitializeDbForTests(ApplicationDbContext db)
{
db.Messages.AddRange(GetSeedingMessages());
db.SaveChanges();
}
public static void ReinitializeDbForTests(ApplicationDbContext db)
{
db.Messages.RemoveRange(db.Messages);
InitializeDbForTests(db);
}
public static List<Message> GetSeedingMessages()
{
return new List<Message>()
{
new Message(){ Text = "TEST RECORD: You're standing on my scarf." },
new Message(){ Text = "TEST RECORD: Would you like a jelly baby?" },
new Message(){ Text = "TEST RECORD: To the rational mind, " +
"nothing is inexplicable; only unexplained." }
};
}
SUT'nin veritabanı bağlamı içinde Program.cs
kaydedilir. Test uygulamasının builder.ConfigureServices
geri çağırması, uygulamanın Program.cs
kodu yürütüldükten sonra yürütülür. Testlerde farklı bir veritabanı kullanmak için uygulamanın veritabanı bağlamı içinde builder.ConfigureServices
değiştirilmelidir. Daha fazla bilgi için WebApplicationFactory'yi Özelleştirme bölümüne bakın.
Ek kaynaklar
Bu konu, birim testlerinin temel bir anlayışını varsayar. Test kavramlarını bilmiyorsanız .NET Core ve .NET Standard'da Birim Testi konusuna ve bağlantılı içeriğine bakın.
Örnek kodu görüntüleme veya indirme (indirme)
Örnek uygulama bir Razor Sayfalar uygulamasıdır ve Sayfalar hakkında temel bir anlayış olduğunu Razor varsayar. Sayfalar'ı bilmiyorsanız Razor aşağıdaki konulara bakın:
Not
SPA'ları test etme amacıyla tarayıcıyı otomatikleştirebilen .NET için Playwright gibi bir araç öneririz.
Tümleştirme testlerine giriş
Tümleştirme testleri, bir uygulamanın bileşenlerini birim testlerinden daha geniş bir düzeyde değerlendirir. Birim testleri, tek tek sınıf yöntemleri gibi yalıtılmış yazılım bileşenlerini test etmek için kullanılır. Tümleştirme testleri, iki veya daha fazla uygulama bileşeninin birlikte çalışarak beklenen bir sonuç elde ettiğini ve büyük olasılıkla bir isteği tam olarak işlemek için gereken her bileşenin de dahil olduğunu onaylar.
Bu daha geniş testler, genellikle aşağıdaki bileşenler de dahil olmak üzere uygulamanın altyapısını ve tüm çerçevesini test etmek için kullanılır:
- Veritabanı
- Dosya sistemi
- Ağ gereçleri
- İstek-yanıt işlem hattı
Birim testleri, altyapı bileşenleri yerine sahte veya sahte nesneler olarak bilinen fabrikatlanmış bileşenleri kullanır.
Birim testlerinin aksine tümleştirme testleri:
- Uygulamanın üretimde kullandığı gerçek bileşenleri kullanın.
- Daha fazla kod ve veri işleme gerektirir.
- Çalıştırılması daha uzun sürer.
Bu nedenle, tümleştirme testlerinin kullanımını en önemli altyapı senaryolarıyla sınırlayın. Bir davranış birim testi veya tümleştirme testi kullanılarak test edilebiliyorsa birim testini seçin.
Tümleştirme testlerinin tartışmalarında, test edilen projeye genellikle Test Altındaki Sistem veya kısaca "SUT" adı verilir. "SUT" bu makalede test edilen ASP.NET Core uygulamasına başvurmak için kullanılır.
Veritabanları ve dosya sistemleriyle verilerin ve dosya erişiminin her permütasyonu için tümleştirme testleri yazmayın. Bir uygulama genelinde veritabanları ve dosya sistemleriyle kaç yerde etkileşim kurduğundan bağımsız olarak, odaklanmış bir dizi okuma, yazma, güncelleştirme ve silme tümleştirme testi genellikle veritabanı ve dosya sistemi bileşenlerini yeterince test edebilmektedir. Bu bileşenlerle etkileşim kuran yöntem mantığının rutin testleri için birim testlerini kullanın. Birim testlerinde, altyapı sahteleri veya sahteleri kullanımı test yürütmenin daha hızlı gerçekleşmesine neden olur.
ASP.NET Core tümleştirme testleri
ASP.NET Core'daki tümleştirme testleri aşağıdakileri gerektirir:
- Testleri içermek ve yürütmek için bir test projesi kullanılır. Test projesinin SUT başvurusu vardır.
- Test projesi SUT için bir test web konağı oluşturur ve SUT ile istekleri ve yanıtları işlemek için bir test sunucusu istemcisi kullanır.
- Testleri yürütmek ve test sonuçlarını raporlamak için bir test çalıştırıcısı kullanılır.
Tümleştirme testleri, her zamanki Düzenleme, Eylem ve Onay testi adımlarını içeren bir dizi olayı izler:
- SUT'nin web konağı yapılandırıldı.
- Uygulamaya istek göndermek için bir test sunucusu istemcisi oluşturulur.
- Test düzenleme adımı yürütülür: Test uygulaması bir istek hazırlar.
- Eylem test adımı yürütülür: İstemci isteği gönderir ve yanıtı alır.
- Assert test adımı yürütülür: Gerçek yanıt, beklenen yanıta göre geçiş veya başarısız olarak doğrulanır.
- Tüm testler yürütülene kadar işlem devam eder.
- Test sonuçları bildirilir.
Genellikle test web konağı, test çalıştırmaları için uygulamanın normal web ana bilgisayarından farklı yapılandırılır. Örneğin, testler için farklı bir veritabanı veya farklı uygulama ayarları kullanılabilir.
Test web konağı ve bellek içi test sunucusu ()TestServer gibi altyapı bileşenleri Microsoft.AspNetCore.Mvc.Testing paketi tarafından sağlanır veya yönetilir. Bu paketin kullanımı test oluşturma ve yürütmeyi kolaylaştırır.
Paket Microsoft.AspNetCore.Mvc.Testing
aşağıdaki görevleri işler:
- Bağımlılık dosyasını (
.deps
) SUT'den test projesininbin
dizinine kopyalar. - testler yürütürken statik dosyaların ve sayfaların/görünümlerin bulunması için içerik kökünü SUT'nin proje köküne ayarlar.
- ile
TestServer
SUT önyüklemesini kolaylaştırmak için WebApplicationFactory sınıfını sağlar.
Birim testleri belgelerinde bir test projesi ve test çalıştırıcısının nasıl ayarlanacağı ve testleri çalıştırma hakkında ayrıntılı yönergelerin yanı sıra testleri ve test sınıflarını adlandırmaya yönelik öneriler açıklanmaktadır.
Birim testlerini tümleştirme testlerinden farklı projelere ayırın. Testleri ayırma:
- Altyapı testi bileşenlerinin birim testlerine yanlışlıkla dahil edilmesini sağlamaya yardımcı olur.
- Hangi test kümesinin çalıştırıldığı üzerinde denetime izin verir.
Sayfalar uygulamalarının ve MVC uygulamalarının testlerinin Razor yapılandırması arasında neredeyse hiçbir fark yoktur. Tek fark, testlerin nasıl adlandırıldığındandır. Razor Sayfalar uygulamasında, sayfa uç noktalarının testleri genellikle sayfa modeli sınıfından (örneğin, IndexPageTests
Dizin sayfası için bileşen tümleştirmesini test etmek için) adlandırılır. MVC uygulamasında testler genellikle denetleyici sınıflarına göre düzenlenir ve test ettikleri denetleyicilerden (örneğin, HomeControllerTests
denetleyici için bileşen tümleştirmesini Home test etmek için) adlandırılır.
Uygulama önkoşullarını test edin
Test projesinin aşağıdakileri yapması gerekir:
Microsoft.AspNetCore.Mvc.Testing
paketine başvurun.- Proje dosyasında (
<Project Sdk="Microsoft.NET.Sdk.Web">
) Web SDK'sını belirtin.
Bu önkoşullar örnek uygulamada görülebilir. tests/RazorPagesProject.Tests/RazorPagesProject.Tests.csproj
Dosyayı inceleyin. Örnek uygulama xUnit test çerçevesini ve AngleSharp ayrıştırıcı kitaplığını kullandığından örnek uygulama da aşağıdakilere başvurur:
Sürüm 2.4.2 veya üzerini kullanan xunit.runner.visualstudio
uygulamalarda test projesinin pakete başvurması Microsoft.NET.Test.Sdk
gerekir.
Entity Framework Core, testlerde de kullanılır. Uygulama şu başvurulara başvurur:
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Microsoft.AspNetCore.Identity.EntityFrameworkCore
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.InMemory
Microsoft.EntityFrameworkCore.Tools
SUT ortamı
SUT'nin ortamı ayarlı değilse, ortam varsayılan olarak Geliştirme olarak ayarlanır.
Varsayılan WebApplicationFactory ile temel testler
WebApplicationFactory<TEntryPoint> tümleştirme testlerine yönelik bir TestServer oluşturmak için kullanılır. TEntryPoint
genellikle sınıfı olan SUT'nin giriş noktası sınıfıdır Startup
.
Test sınıfları, sınıfın testleri içerdiğini belirtmek ve sınıftaki testler arasında paylaşılan nesne örnekleri sağlamak için bir sınıf fikstür arabirimi (IClassFixture
) uygular.
Aşağıdaki test sınıfı, BasicTests
SUT'yi önyüklemek ve bir test yöntemi Get_EndpointsReturnSuccessAndCorrectContentType
sağlamak HttpClient için öğesini kullanırWebApplicationFactory
. yöntemi, yanıt durum kodunun başarılı olup olmadığını (200-299 aralığındaki durum kodları) ve Content-Type
üst bilginin birkaç uygulama sayfası için olup olmadığını text/html; charset=utf-8
denetler.
CreateClient() otomatik olarak yeniden yönlendirmeleri izleyen ve tanımlama bilgilerini işleyen bir örneği HttpClient
oluşturur.
public class BasicTests
: IClassFixture<WebApplicationFactory<RazorPagesProject.Startup>>
{
private readonly WebApplicationFactory<RazorPagesProject.Startup> _factory;
public BasicTests(WebApplicationFactory<RazorPagesProject.Startup> factory)
{
_factory = factory;
}
[Theory]
[InlineData("/")]
[InlineData("/Index")]
[InlineData("/About")]
[InlineData("/Privacy")]
[InlineData("/Contact")]
public async Task Get_EndpointsReturnSuccessAndCorrectContentType(string url)
{
// Arrange
var client = _factory.CreateClient();
// Act
var response = await client.GetAsync(url);
// Assert
response.EnsureSuccessStatusCode(); // Status Code 200-299
Assert.Equal("text/html; charset=utf-8",
response.Content.Headers.ContentType.ToString());
}
}
Varsayılan olarak, GDPR onay ilkesi etkinleştirildiğinde gerekli olmayan tanımlama bilgileri istekler arasında korunmaz. TempData sağlayıcısı tarafından kullanılanlar gibi temel olmayan tanımlama bilgilerini korumak için bunları testlerinizde temel olarak işaretleyin. Temel olarak işaretleme cookie yönergeleri için bkz . Temel tanımlama bilgileri.
WebApplicationFactory'i özelleştirme
Web ana bilgisayar yapılandırması, bir veya daha fazla özel fabrika oluşturmak için öğesinden devralınarak test sınıflarından WebApplicationFactory
bağımsız olarak oluşturulabilir:
öğesinden
WebApplicationFactory
devralın ve öğesini geçersiz kılın ConfigureWebHost. ile IWebHostBuilder hizmet koleksiyonunun ConfigureServicesyapılandırılmasına izin verir:public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup: class { protected override void ConfigureWebHost(IWebHostBuilder builder) { builder.ConfigureServices(services => { var descriptor = services.SingleOrDefault( d => d.ServiceType == typeof(DbContextOptions<ApplicationDbContext>)); services.Remove(descriptor); services.AddDbContext<ApplicationDbContext>(options => { options.UseInMemoryDatabase("InMemoryDbForTesting"); }); var sp = services.BuildServiceProvider(); using (var scope = sp.CreateScope()) { var scopedServices = scope.ServiceProvider; var db = scopedServices.GetRequiredService<ApplicationDbContext>(); var logger = scopedServices .GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>(); db.Database.EnsureCreated(); try { Utilities.InitializeDbForTests(db); } catch (Exception ex) { logger.LogError(ex, "An error occurred seeding the " + "database with test messages. Error: {Message}", ex.Message); } } }); } }
Örnek uygulamadaki veritabanı tohumlama yöntemi tarafından
InitializeDbForTests
gerçekleştirilir. Yöntemi, Tümleştirme testleri örneği: Test uygulaması kuruluşu bölümünde açıklanmıştır.SUT'nin veritabanı bağlamı yöntemine
Startup.ConfigureServices
kaydedilir. Test uygulamasınınbuilder.ConfigureServices
geri çağırması, uygulamanınStartup.ConfigureServices
kodu yürütüldükten sonra yürütülür. Yürütme sırası, ASP.NET Core 3.0 sürümüyle Genel Ana Bilgisayar için hataya neden olan bir değişikliktir. Testlerde uygulamanın veritabanından farklı bir veritabanı kullanmak için, uygulamanın veritabanı bağlamı içindebuilder.ConfigureServices
değiştirilmelidir.Web Konağını kullanmaya devam eden SUT'ler için test uygulamasının
builder.ConfigureServices
geri çağırması SUTStartup.ConfigureServices
kodundan önce yürütülür. Test uygulamasınınbuilder.ConfigureTestServices
geri çağırması daha sonra yürütülür.Örnek uygulama, veritabanı bağlamı için hizmet tanımlayıcısını bulur ve hizmet kaydını kaldırmak için tanımlayıcıyı kullanır. Ardından fabrika, testler için bellek içi veritabanı kullanan yeni
ApplicationDbContext
bir veritabanı ekler.Bellek içi veritabanından farklı bir veritabanına bağlanmak için, bağlamı
UseInMemoryDatabase
farklı bir veritabanına bağlamak için çağrıyı değiştirin. SQL Server test veritabanını kullanmak için:- Proje dosyasındaKi
Microsoft.EntityFrameworkCore.SqlServer
NuGet paketine başvurun. - Veritabanına bir bağlantı dizesi ile çağrısı
UseSqlServer
yapın.
services.AddDbContext<ApplicationDbContext>((options, context) => { context.UseSqlServer( Configuration.GetConnectionString("TestingDbConnectionString")); });
- Proje dosyasındaKi
Test sınıflarında özel
CustomWebApplicationFactory
öğesini kullanın. Aşağıdaki örnekte sınıfındakiIndexPageTests
fabrika kullanılır:public class IndexPageTests : IClassFixture<CustomWebApplicationFactory<RazorPagesProject.Startup>> { private readonly HttpClient _client; private readonly CustomWebApplicationFactory<RazorPagesProject.Startup> _factory; public IndexPageTests( CustomWebApplicationFactory<RazorPagesProject.Startup> factory) { _factory = factory; _client = factory.CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false }); }
Örnek uygulamanın istemcisi, aşağıdaki yeniden yönlendirmelerin
HttpClient
engellenmesi için yapılandırılır. Sahte kimlik doğrulaması bölümünde daha sonra açıklandığı gibi bu, testlerin uygulamanın ilk yanıtının sonucunu denetlemesine izin verir. İlk yanıt, bu testlerin çoğunda üst bilgi içeren birLocation
yeniden yönlendirmedir.Tipik bir test, isteği ve yanıtı işlemek için ve yardımcı yöntemlerini kullanır
HttpClient
:[Fact] public async Task Post_DeleteAllMessagesHandler_ReturnsRedirectToRoot() { // Arrange var defaultPage = await _client.GetAsync("/"); var content = await HtmlHelpers.GetDocumentAsync(defaultPage); //Act var response = await _client.SendAsync( (IHtmlFormElement)content.QuerySelector("form[id='messages']"), (IHtmlButtonElement)content.QuerySelector("button[id='deleteAllBtn']")); // Assert Assert.Equal(HttpStatusCode.OK, defaultPage.StatusCode); Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); Assert.Equal("/", response.Headers.Location.OriginalString); }
SUT'ye yapılan herhangi bir POST isteği, uygulamanın veri koruma önleme sistemi tarafından otomatik olarak yapılan kötü amaçlı yazılımdan koruma denetimini karşılamalıdır. Testin POST isteğini düzenlemek için test uygulamasının şunları yapması gerekir:
- Sayfa için bir istekte bulun.
- Antiforgery'yi cookie ayrıştırın ve yanıttan doğrulama belirteci isteyin.
- POST isteğini sahteciliğe cookie karşı koruma ve istek doğrulama belirteci ile gerçekleştirin.
Örnek SendAsync
uygulamadaki GetDocumentAsync
yardımcı uzantı yöntemleri (Helpers/HttpClientExtensions.cs
) ve yardımcı yöntemi (Helpers/HtmlHelpers.cs
), aşağıdaki yöntemlerle antiforgery denetimini işlemek için AngleSharp ayrıştırıcısını kullanır:
GetDocumentAsync
: alır HttpResponseMessage ve döndürürIHtmlDocument
.GetDocumentAsync
, özgünHttpResponseMessage
öğesini temel alan bir sanal yanıt hazırlayan bir fabrika kullanır. Daha fazla bilgi için AngleSharp belgelerine bakın.SendAsync
oluşturma HttpRequestMessage ve SUT'ye istek gönderme çağrısı SendAsync(HttpRequestMessage) için uzantı yöntemleriHttpClient
. HTML formunu (IHtmlFormElement
) ve aşağıdakileri kabul etmek içinSendAsync
aşırı yüklemeler:- Formun Gönder düğmesi (
IHtmlElement
) - Form değerleri koleksiyonu (
IEnumerable<KeyValuePair<string, string>>
) - Gönder düğmesi (
IHtmlElement
) ve form değerleri (IEnumerable<KeyValuePair<string, string>>
)
- Formun Gönder düğmesi (
Not
AngleSharp , bu konuda ve örnek uygulamada gösterim amacıyla kullanılan bir üçüncü taraf ayrıştırma kitaplığıdır. AngleSharp, ASP.NET Core uygulamalarının tümleştirme testi için desteklenmez veya gerekli değildir. Html Çeviklik Paketi (HAP) gibi diğer ayrıştırıcılar kullanılabilir. Bir diğer yaklaşım da, sahteciliğe karşı koruma sisteminin istek doğrulama belirtecini ve kötü amaçlı yazılımdan korumayı doğrudan işlemek için kod yazmaktır cookie .
Not
EF-Core bellek içi veritabanı sağlayıcısı sınırlı ve temel test için kullanılabilir, ancak bellek içi test için önerilen seçenek SQLite sağlayıcısıdır.
WithWebHostBuilder ile istemciyi özelleştirme
Bir test yönteminde ek yapılandırma gerektiğinde, WithWebHostBuilder yapılandırma tarafından daha da özelleştirilmiş bir ile yeni WebApplicationFactory
bir IWebHostBuilder oluşturur.
Post_DeleteMessageHandler_ReturnsRedirectToRoot
Örnek uygulamanın test yöntemi, kullanımını WithWebHostBuilder
gösterir. Bu test, SUT'da form gönderimini tetikleyerek veritabanında bir kayıt silme işlemi gerçekleştirir.
sınıfındaki IndexPageTests
başka bir test veritabanındaki tüm kayıtları silen ve yönteminden önce Post_DeleteMessageHandler_ReturnsRedirectToRoot
çalıştırabilen bir işlem gerçekleştirdiğinden, SUT'nin silmesi için bir kaydın mevcut olduğundan emin olmak için bu test yönteminde veritabanı yeniden görüntülenir. SUT'daki formun ilk sil düğmesinin messages
seçilmesi, SUT isteğinde benzetim yapılır:
[Fact]
public async Task Post_DeleteMessageHandler_ReturnsRedirectToRoot()
{
// Arrange
var client = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
var serviceProvider = services.BuildServiceProvider();
using (var scope = serviceProvider.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var db = scopedServices
.GetRequiredService<ApplicationDbContext>();
var logger = scopedServices
.GetRequiredService<ILogger<IndexPageTests>>();
try
{
Utilities.ReinitializeDbForTests(db);
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred seeding " +
"the database with test messages. Error: {Message}",
ex.Message);
}
}
});
})
.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
var defaultPage = await client.GetAsync("/");
var content = await HtmlHelpers.GetDocumentAsync(defaultPage);
//Act
var response = await client.SendAsync(
(IHtmlFormElement)content.QuerySelector("form[id='messages']"),
(IHtmlButtonElement)content.QuerySelector("form[id='messages']")
.QuerySelector("div[class='panel-body']")
.QuerySelector("button"));
// Assert
Assert.Equal(HttpStatusCode.OK, defaultPage.StatusCode);
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
Assert.Equal("/", response.Headers.Location.OriginalString);
}
İstemci seçenekleri
Aşağıdaki tabloda, örnekler oluşturulurken HttpClient
kullanılabilen varsayılan WebApplicationFactoryClientOptions değer gösterilmektedir.
Seçenek | Açıklama | Varsayılan |
---|---|---|
AllowAutoRedirect | Örneklerin yeniden yönlendirme yanıtlarını otomatik olarak izlemesi gerekip gerekmediğini HttpClient alır veya ayarlar. |
true |
BaseAddress | Örneklerin temel adresini HttpClient alır veya ayarlar. |
http://localhost |
HandleCookies | Örneklerin tanımlama bilgilerini işleyip işlemeyeceğini HttpClient alır veya ayarlar. |
true |
MaxAutomaticRedirections | Örneklerin izlemesi gereken en fazla yeniden yönlendirme yanıt HttpClient sayısını alır veya ayarlar. |
7 |
sınıfını WebApplicationFactoryClientOptions
oluşturun ve yöntemine CreateClient() geçirin (varsayılan değerler kod örneğinde gösterilir):
// Default client option values are shown
var clientOptions = new WebApplicationFactoryClientOptions();
clientOptions.AllowAutoRedirect = true;
clientOptions.BaseAddress = new Uri("http://localhost");
clientOptions.HandleCookies = true;
clientOptions.MaxAutomaticRedirections = 7;
_client = _factory.CreateClient(clientOptions);
Sahte hizmetler ekleme
Hizmetler, konak oluşturucusunda çağrısı ConfigureTestServices yapılan bir testte geçersiz kılınabilir. Sahte hizmetler eklemek için SUT'nin bir yöntemi olan bir Startup
Startup.ConfigureServices
sınıfı olmalıdır.
Örnek SUT, teklif döndüren kapsamlı bir hizmet içerir. Teklif, Dizin sayfası istendiğinde Dizin sayfasındaki gizli bir alana eklenir.
Services/IQuoteService.cs
:
public interface IQuoteService
{
Task<string> GenerateQuote();
}
Services/QuoteService.cs
:
// Quote ©1975 BBC: The Doctor (Tom Baker); Dr. Who: Planet of Evil
// https://www.bbc.co.uk/programmes/p00pyrx6
public class QuoteService : IQuoteService
{
public Task<string> GenerateQuote()
{
return Task.FromResult<string>(
"Come on, Sarah. We've an appointment in London, " +
"and we're already 30,000 years late.");
}
}
Startup.cs
:
services.AddScoped<IQuoteService, QuoteService>();
Pages/Index.cshtml.cs
:
public class IndexModel : PageModel
{
private readonly ApplicationDbContext _db;
private readonly IQuoteService _quoteService;
public IndexModel(ApplicationDbContext db, IQuoteService quoteService)
{
_db = db;
_quoteService = quoteService;
}
[BindProperty]
public Message Message { get; set; }
public IList<Message> Messages { get; private set; }
[TempData]
public string MessageAnalysisResult { get; set; }
public string Quote { get; private set; }
public async Task OnGetAsync()
{
Messages = await _db.GetMessagesAsync();
Quote = await _quoteService.GenerateQuote();
}
Pages/Index.cs
:
<input id="quote" type="hidden" value="@Model.Quote">
SUT uygulaması çalıştırıldığında aşağıdaki işaretleme oluşturulur:
<input id="quote" type="hidden" value="Come on, Sarah. We've an appointment in
London, and we're already 30,000 years late.">
Tümleştirme testinde hizmeti ve teklif eklemeyi test etmek için test tarafından SUT'ye sahte hizmet eklenir. Sahte hizmet, uygulamanın yerine test uygulaması QuoteService
tarafından sağlanan ve adlı TestQuoteService
bir hizmettir:
IntegrationTests.IndexPageTests.cs
:
// Quote ©1975 BBC: The Doctor (Tom Baker); Pyramids of Mars
// https://www.bbc.co.uk/programmes/p00pys55
public class TestQuoteService : IQuoteService
{
public Task<string> GenerateQuote()
{
return Task.FromResult<string>(
"Something's interfering with time, Mr. Scarman, " +
"and time is my business.");
}
}
ConfigureTestServices
çağrılır ve kapsamı belirlenmiş hizmet kaydedilir:
[Fact]
public async Task Get_QuoteService_ProvidesQuoteInPage()
{
// Arrange
var client = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.AddScoped<IQuoteService, TestQuoteService>();
});
})
.CreateClient();
//Act
var defaultPage = await client.GetAsync("/");
var content = await HtmlHelpers.GetDocumentAsync(defaultPage);
var quoteElement = content.QuerySelector("#quote");
// Assert
Assert.Equal("Something's interfering with time, Mr. Scarman, " +
"and time is my business.", quoteElement.Attributes["value"].Value);
}
Testin yürütülmesi sırasında oluşturulan işaretleme, tarafından TestQuoteService
sağlanan tırnak metnini yansıtır, böylece onay geçer:
<input id="quote" type="hidden" value="Something's interfering with time,
Mr. Scarman, and time is my business.">
Sahte kimlik doğrulaması
Sınıfındaki AuthTests
testler güvenli bir uç nokta olup olmadığını denetler:
- Kimliği doğrulanmamış bir kullanıcıyı uygulamanın Oturum Açma sayfasına yönlendirir.
- Kimliği doğrulanmış bir kullanıcının içeriğini döndürür.
SUT'de sayfa, /SecurePage
sayfaya uygulamak için bir AuthorizePage AuthorizeFilter kural kullanır. Daha fazla bilgi için bkz Razor . Sayfa yetkilendirme kuralları.
services.AddRazorPages(options =>
{
options.Conventions.AuthorizePage("/SecurePage");
});
Testte Get_SecurePageRedirectsAnUnauthenticatedUser
, ayarı WebApplicationFactoryClientOptions olarak ayarlanarak AllowAutoRedirect yeniden yönlendirmelere izin vermemeye false
ayarlanmıştır:
[Fact]
public async Task Get_SecurePageRedirectsAnUnauthenticatedUser()
{
// Arrange
var client = _factory.CreateClient(
new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
// Act
var response = await client.GetAsync("/SecurePage");
// Assert
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
Assert.StartsWith("http://localhost/Identity/Account/Login",
response.Headers.Location.OriginalString);
}
İstemcinin yeniden yönlendirmeyi izlemesine izin vermeyerek aşağıdaki denetimler yapılabilir:
- SUT tarafından döndürülen durum kodu, Oturum Açma sayfasına yönlendirildikten sonraki son durum koduna değil beklenen HttpStatusCode.Redirect sonucta göre denetlenebilir. Bu, olur HttpStatusCode.OK.
- Yanıt
Location
üst bilgilerindeki üst bilgi değeri, üst bilginin mevcut olmadığı son Oturum Açma sayfası yanıtıyla değil ileLocation
başladığınıhttp://localhost/Identity/Account/Login
onaylamak için denetlendi.
Test uygulaması, kimlik doğrulaması ve yetkilendirme özelliklerini test etmek için bir AuthenticationHandler<TOptions> ConfigureTestServices ile dalga geçebilir. En düşük senaryo bir AuthenticateResult.Successdöndürür:
public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public TestAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var claims = new[] { new Claim(ClaimTypes.Name, "Test user") };
var identity = new ClaimsIdentity(claims, "Test");
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, "Test");
var result = AuthenticateResult.Success(ticket);
return Task.FromResult(result);
}
}
TestAuthHandler
, kimlik doğrulama düzeni için kaydedildiği yere AddAuthentication
ayarlandığında Test
kullanıcının kimliğini doğrulamak için ConfigureTestServices
çağrılır. Düzenin uygulamanızın Test
beklediği düzenle eşleşmesi önemlidir. Aksi takdirde kimlik doğrulaması çalışmaz.
[Fact]
public async Task Get_SecurePageIsReturnedForAnAuthenticatedUser()
{
// Arrange
var client = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(
"Test", options => {});
});
})
.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false,
});
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Test");
//Act
var response = await client.GetAsync("/SecurePage");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
hakkında WebApplicationFactoryClientOptions
daha fazla bilgi için İstemci seçenekleri bölümüne bakın.
Ortamı ayarlama
Varsayılan olarak, SUT'nin ana bilgisayar ve uygulama ortamı Geliştirme ortamını kullanacak şekilde yapılandırılır. kullanırken IHostBuilder
SUT ortamını geçersiz kılmak için:
- Ortam değişkenini
ASPNETCORE_ENVIRONMENT
(örneğin,Staging
,Production
veya gibi başka bir özel değer)Testing
ayarlayın. - ön ekli
ASPNETCORE
ortam değişkenlerini okumak için test uygulamasında geçersiz kılınCreateHostBuilder
.
protected override IHostBuilder CreateHostBuilder() =>
base.CreateHostBuilder()
.ConfigureHostConfiguration(
config => config.AddEnvironmentVariables("ASPNETCORE"));
SUT Web Konağını ()IWebHostBuilder
kullanıyorsa, geçersiz kılın CreateWebHostBuilder
:
protected override IWebHostBuilder CreateWebHostBuilder() =>
base.CreateWebHostBuilder().UseEnvironment("Testing");
Test altyapısı uygulama içeriği kök yolunu nasıl çıkarsar?
Oluşturucu, WebApplicationFactory
derlemeye eşit TEntryPoint
bir WebApplicationFactoryContentRootAttribute anahtara sahip tümleştirme testlerini içeren derlemede öğesini arayarak uygulama içeriği kök yolunu çıkarsarSystem.Reflection.Assembly.FullName
. Doğru anahtara sahip bir özniteliğin bulunamazsa, WebApplicationFactory
çözüm dosyasını aramaya (.sln) geri döner ve derleme adını çözüm dizinine ekler TEntryPoint
. Uygulama kök dizini (içerik kök yolu), görünümleri ve içerik dosyalarını bulmak için kullanılır.
Gölge kopyalamayı devre dışı bırakma
Gölge kopyalama, testlerin çıkış dizininden farklı bir dizinde yürütülmesine neden olur. Testleriniz ile ilgili Assembly.Location
dosyaları yüklemeye bağlıysa ve sorunlarla karşılaşıyorsanız, gölge kopyalamayı devre dışı bırakmanız gerekebilir.
xUnit kullanırken gölge kopyalamayı devre dışı bırakmak için test projesi dizininizde doğru yapılandırma ayarıyla bir xunit.runner.json
dosya oluşturun:
{
"shadowCopy": false
}
Nesnelerin atılması
Uygulamanın testleri IClassFixture
yürütüldükten TestServer ve HttpClient xUnit WebApplicationFactory
tarafından atıldığında atılır. Geliştirici tarafından örneği oluşturulmuş nesneler elden çıkarılma gerektiriyorsa, bunları IClassFixture
uygulamada atın. Daha fazla bilgi için bkz . Dispose yöntemi uygulama.
Tümleştirme testleri örneği
Örnek uygulama iki uygulamadan oluşur:
Uygulama | Proje dizini | Açıklama |
---|---|---|
İleti uygulaması (SUT) | src/RazorPagesProject |
Kullanıcının bir ileti eklemesine, silmesine, tümünü silmesine ve iletileri analiz etmesine izin verir. |
Test uygulaması | tests/RazorPagesProject.Tests |
SUT'yi tümleştirme 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, dizindeki bir komut isteminde aşağıdaki komutu yürütürtests/RazorPagesProject.Tests
:
dotnet test
İleti uygulaması (SUT) kuruluşu
SUT, 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 (ileti başına ortalama sözcükler) denetlemek için bir kullanıcı arabirimi ve sayfa modeli yöntemleri sağlar. - 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
() bir veri erişim katmanı (Data/AppDbContext.cs
DAL) içerir. - Uygulama başlangıcında veritabanı boşsa, ileti deposu üç iletiyle başlatılır.
- Uygulama yalnızca kimliği doğrulanmış bir
/SecurePage
kullanıcı tarafından erişilebilen bir içerir.
†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.
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 Test denetleyicisi mantığı (örnek, depo düzenini uygular).
Uygulama kuruluşunu test et
Test uygulaması, dizinin içindeki tests/RazorPagesProject.Tests
bir konsol uygulamasıdır.
Uygulama dizinini test et | Açıklama |
---|---|
AuthTests |
Aşağıdakiler için test yöntemlerini içerir:
|
BasicTests |
Yönlendirme ve içerik türü için bir test yöntemi içerir. |
IntegrationTests |
Özel WebApplicationFactory sınıf kullanarak Dizin sayfasının tümleştirme testlerini içerir. |
Helpers/Utilities |
|
Test çerçevesi xUnit'tir. Tümleştirme testleri, öğesini içeren TestServerkullanılarak Microsoft.AspNetCore.TestHostyapılır. Microsoft.AspNetCore.Mvc.Testing
Paket test ana bilgisayarını ve test sunucusunu yapılandırmak için kullanıldığından TestHost
ve TestServer
paketleri, test uygulamasının proje dosyasında veya test uygulamasındaki geliştirici yapılandırmasında doğrudan paket başvuruları gerektirmez.
Tümleştirme testleri genellikle test yürütmeden önce veritabanında küçük bir veri kümesi gerektirir. Örneğin, silme testi veritabanı kaydı silme işlemini çağırır, bu nedenle silme isteğinin başarılı olması için veritabanında en az bir kayıt olmalıdır.
Örnek uygulama, testleri yürütürken kullanabileceği üç iletiyle Utilities.cs
veritabanının çekirdeğini oluşturur:
public static void InitializeDbForTests(ApplicationDbContext db)
{
db.Messages.AddRange(GetSeedingMessages());
db.SaveChanges();
}
public static void ReinitializeDbForTests(ApplicationDbContext db)
{
db.Messages.RemoveRange(db.Messages);
InitializeDbForTests(db);
}
public static List<Message> GetSeedingMessages()
{
return new List<Message>()
{
new Message(){ Text = "TEST RECORD: You're standing on my scarf." },
new Message(){ Text = "TEST RECORD: Would you like a jelly baby?" },
new Message(){ Text = "TEST RECORD: To the rational mind, " +
"nothing is inexplicable; only unexplained." }
};
}
SUT'nin veritabanı bağlamı yöntemine Startup.ConfigureServices
kaydedilir. Test uygulamasının builder.ConfigureServices
geri çağırması, uygulamanın Startup.ConfigureServices
kodu yürütüldükten sonra yürütülür. Testlerde farklı bir veritabanı kullanmak için uygulamanın veritabanı bağlamı içinde builder.ConfigureServices
değiştirilmelidir. Daha fazla bilgi için WebApplicationFactory'yi Özelleştirme bölümüne bakın.
Web Konağını kullanmaya devam eden SUT'ler için test uygulamasının builder.ConfigureServices
geri çağırması SUT Startup.ConfigureServices
kodundan önce yürütülür. Test uygulamasının builder.ConfigureTestServices
geri çağırması daha sonra yürütülür.
Ek kaynaklar
Bu makalede, birim testleri hakkında temel bilgiler olduğu varsayılır. Test kavramlarını bilmiyorsanız .NET Core ve .NET Standard'da Birim Testi makalesine ve bağlantılı içeriğine bakın.
Örnek kodu görüntüleme veya indirme (indirme)
Örnek uygulama bir Razor Sayfalar uygulamasıdır ve Sayfalar hakkında temel bir anlayış olduğunu Razor varsayar. Pages'ı tanımıyorsanız Razor aşağıdaki makalelere bakın:
SPA'ları test etme amacıyla tarayıcıyı otomatikleştirebilen .NET için Playwright gibi bir araç öneririz.
Tümleştirme testlerine giriş
Tümleştirme testleri, bir uygulamanın bileşenlerini birim testlerinden daha geniş bir düzeyde değerlendirir. Birim testleri, tek tek sınıf yöntemleri gibi yalıtılmış yazılım bileşenlerini test etmek için kullanılır. Tümleştirme testleri, iki veya daha fazla uygulama bileşeninin birlikte çalışarak beklenen bir sonuç elde ettiğini ve büyük olasılıkla bir isteği tam olarak işlemek için gereken her bileşenin de dahil olduğunu onaylar.
Bu daha geniş testler, genellikle aşağıdaki bileşenler de dahil olmak üzere uygulamanın altyapısını ve tüm çerçevesini test etmek için kullanılır:
- Veritabanı
- Dosya sistemi
- Ağ gereçleri
- İstek-yanıt işlem hattı
Birim testleri, altyapı bileşenleri yerine sahte veya sahte nesneler olarak bilinen fabrikatlanmış bileşenleri kullanır.
Birim testlerinin aksine tümleştirme testleri:
- Uygulamanın üretimde kullandığı gerçek bileşenleri kullanın.
- Daha fazla kod ve veri işleme gerektirir.
- Çalıştırılması daha uzun sürer.
Bu nedenle, tümleştirme testlerinin kullanımını en önemli altyapı senaryolarıyla sınırlayın. Bir davranış birim testi veya tümleştirme testi kullanılarak test edilebiliyorsa birim testini seçin.
Tümleştirme testlerinin tartışmalarında, test edilen projeye genellikle Test Altındaki Sistem veya kısaca "SUT" adı verilir. "SUT" bu makalede test edilen ASP.NET Core uygulamasına başvurmak için kullanılır.
Veritabanları ve dosya sistemleriyle verilerin ve dosya erişiminin her permütasyonu için tümleştirme testleri yazmayın. Bir uygulama genelinde veritabanları ve dosya sistemleriyle kaç yerde etkileşim kurduğundan bağımsız olarak, odaklanmış bir dizi okuma, yazma, güncelleştirme ve silme tümleştirme testi genellikle veritabanı ve dosya sistemi bileşenlerini yeterince test edebilmektedir. Bu bileşenlerle etkileşim kuran yöntem mantığının rutin testleri için birim testlerini kullanın. Birim testlerinde, altyapı sahteleri veya sahteleri kullanımı test yürütmenin daha hızlı gerçekleşmesine neden olur.
ASP.NET Core tümleştirme testleri
ASP.NET Core'daki tümleştirme testleri aşağıdakileri gerektirir:
- Testleri içermek ve yürütmek için bir test projesi kullanılır. Test projesinin SUT başvurusu vardır.
- Test projesi SUT için bir test web konağı oluşturur ve SUT ile istekleri ve yanıtları işlemek için bir test sunucusu istemcisi kullanır.
- Testleri yürütmek ve test sonuçlarını raporlamak için bir test çalıştırıcısı kullanılır.
Tümleştirme testleri, her zamanki Düzenleme, Eylem ve Onay testi adımlarını içeren bir dizi olayı izler:
- SUT'nin web konağı yapılandırıldı.
- Uygulamaya istek göndermek için bir test sunucusu istemcisi oluşturulur.
- Test düzenleme adımı yürütülür: Test uygulaması bir istek hazırlar.
- Eylem test adımı yürütülür: İstemci isteği gönderir ve yanıtı alır.
- Assert test adımı yürütülür: Gerçek yanıt, beklenen yanıta göre geçiş veya başarısız olarak doğrulanır.
- Tüm testler yürütülene kadar işlem devam eder.
- Test sonuçları bildirilir.
Genellikle test web konağı, test çalıştırmaları için uygulamanın normal web ana bilgisayarından farklı yapılandırılır. Örneğin, testler için farklı bir veritabanı veya farklı uygulama ayarları kullanılabilir.
Test web konağı ve bellek içi test sunucusu ()TestServer gibi altyapı bileşenleri Microsoft.AspNetCore.Mvc.Testing paketi tarafından sağlanır veya yönetilir. Bu paketin kullanımı test oluşturma ve yürütmeyi kolaylaştırır.
Paket Microsoft.AspNetCore.Mvc.Testing
aşağıdaki görevleri işler:
- Bağımlılık dosyasını (
.deps
) SUT'den test projesininbin
dizinine kopyalar. - testler yürütürken statik dosyaların ve sayfaların/görünümlerin bulunması için içerik kökünü SUT'nin proje köküne ayarlar.
- ile
TestServer
SUT önyüklemesini kolaylaştırmak için WebApplicationFactory sınıfını sağlar.
Birim testleri belgelerinde bir test projesi ve test çalıştırıcısının nasıl ayarlanacağı ve testleri çalıştırma hakkında ayrıntılı yönergelerin yanı sıra testleri ve test sınıflarını adlandırmaya yönelik öneriler açıklanmaktadır.
Birim testlerini tümleştirme testlerinden farklı projelere ayırın. Testleri ayırma:
- Altyapı testi bileşenlerinin birim testlerine yanlışlıkla dahil edilmesini sağlamaya yardımcı olur.
- Hangi test kümesinin çalıştırıldığı üzerinde denetime izin verir.
Sayfalar uygulamalarının ve MVC uygulamalarının testlerinin Razor yapılandırması arasında neredeyse hiçbir fark yoktur. Tek fark, testlerin nasıl adlandırıldığındandır. Razor Sayfalar uygulamasında, sayfa uç noktalarının testleri genellikle sayfa modeli sınıfından (örneğin, IndexPageTests
Dizin sayfası için bileşen tümleştirmesini test etmek için) adlandırılır. MVC uygulamasında testler genellikle denetleyici sınıflarına göre düzenlenir ve test ettikleri denetleyicilerden (örneğin, HomeControllerTests
denetleyici için bileşen tümleştirmesini Home test etmek için) adlandırılır.
Uygulama önkoşullarını test edin
Test projesinin aşağıdakileri yapması gerekir:
Microsoft.AspNetCore.Mvc.Testing
paketine başvurun.- Proje dosyasında (
<Project Sdk="Microsoft.NET.Sdk.Web">
) Web SDK'sını belirtin.
Bu önkoşullar örnek uygulamada görülebilir. tests/RazorPagesProject.Tests/RazorPagesProject.Tests.csproj
Dosyayı inceleyin. Örnek uygulama xUnit test çerçevesini ve AngleSharp ayrıştırıcı kitaplığını kullandığından örnek uygulama da aşağıdakilere başvurur:
Sürüm 2.4.2 veya üzerini kullanan xunit.runner.visualstudio
uygulamalarda test projesinin pakete başvurması Microsoft.NET.Test.Sdk
gerekir.
Entity Framework Core, testlerde de kullanılır. GitHub'daki proje dosyasına bakın.
SUT ortamı
SUT'nin ortamı ayarlı değilse, ortam varsayılan olarak Geliştirme olarak ayarlanır.
Varsayılan WebApplicationFactory ile temel testler
Aşağıdakilerden birini yaparak örtük olarak tanımlanmış Program
sınıfı test projesinde kullanıma sunma:
Web uygulamasından test projesine iç türleri kullanıma sunma. Bu işlem SUT projesinin dosyasında (
.csproj
):<ItemGroup> <InternalsVisibleTo Include="MyTestProject" /> </ItemGroup>
Program
Kısmi bir sınıf bildirimi kullanarak sınıfını genel yapın:var builder = WebApplication.CreateBuilder(args); // ... Configure services, routes, etc. app.Run(); + public partial class Program { }
Örnek uygulama kısmi sınıf yaklaşımını
Program
kullanır.
WebApplicationFactory<TEntryPoint> tümleştirme testlerine yönelik bir TestServer oluşturmak için kullanılır. TEntryPoint
genellikle Program.cs
SUT'nin giriş noktası sınıfıdır.
Test sınıfları, sınıfın testleri içerdiğini belirtmek ve sınıftaki testler arasında paylaşılan nesne örnekleri sağlamak için bir sınıf fikstür arabirimi (IClassFixture
) uygular.
Aşağıdaki test sınıfı, BasicTests
SUT'yi önyüklemek ve bir test yöntemi Get_EndpointsReturnSuccessAndCorrectContentType
sağlamak HttpClient için öğesini kullanırWebApplicationFactory
. yöntemi, yanıt durum kodunun başarılı olduğunu (200-299) ve Content-Type
üst bilgi de birkaç uygulama sayfası için doğrular text/html; charset=utf-8
.
CreateClient() otomatik olarak yeniden yönlendirmeleri izleyen ve tanımlama bilgilerini işleyen bir örneği HttpClient
oluşturur.
public class BasicTests
: IClassFixture<WebApplicationFactory<Program>>
{
private readonly WebApplicationFactory<Program> _factory;
public BasicTests(WebApplicationFactory<Program> factory)
{
_factory = factory;
}
[Theory]
[InlineData("/")]
[InlineData("/Index")]
[InlineData("/About")]
[InlineData("/Privacy")]
[InlineData("/Contact")]
public async Task Get_EndpointsReturnSuccessAndCorrectContentType(string url)
{
// Arrange
var client = _factory.CreateClient();
// Act
var response = await client.GetAsync(url);
// Assert
response.EnsureSuccessStatusCode(); // Status Code 200-299
Assert.Equal("text/html; charset=utf-8",
response.Content.Headers.ContentType.ToString());
}
}
Varsayılan olarak, Genel Veri Koruma Yönetmeliği onay ilkesi etkinleştirildiğinde gerekli olmayan tanımlama bilgileri istekler arasında korunmaz. TempData sağlayıcısı tarafından kullanılanlar gibi temel olmayan tanımlama bilgilerini korumak için bunları testlerinizde temel olarak işaretleyin. Temel olarak işaretleme cookie yönergeleri için bkz . Temel tanımlama bilgileri.
AngleSharp ile Application Parts
antiforgery denetimleri karşılaştırması
Bu makalede, sayfaları yükleyerek ve HTML ayrıştırarak antiforgery denetimlerini işlemek için AngleSharp ayrıştırıcısı kullanılır. Denetleyici ve Razor Sayfalar görünümlerinin uç noktalarını tarayıcıda nasıl işlediklerine önem vermeden daha düşük bir düzeyde test için kullanmayı Application Parts
göz önünde bulundurun. Uygulama Bölümleri yaklaşımı, uygulamaya gerekli değerleri almak için JSON isteklerinde bulunmak için kullanılabilecek bir denetleyici veya Razor Sayfa ekler. Daha fazla bilgi için Bkz. Tümleştirme Testi ASP.NET Uygulama Bölümlerini Kullanarak Sahtekarlık Önleme ile Korunan Temel Kaynaklar ve Martin Costello tarafından ilişkili GitHub deposu.
WebApplicationFactory'i özelleştirme
Web ana bilgisayar yapılandırması, bir veya daha fazla özel fabrika oluşturmak için öğesinden devralınarak test sınıflarından WebApplicationFactory<TEntryPoint> bağımsız olarak oluşturulabilir:
öğesinden
WebApplicationFactory
devralın ve öğesini geçersiz kılın ConfigureWebHost. ile IWebHostBuilder hizmet koleksiyonunun yapılandırılmasına izin verirIWebHostBuilder.ConfigureServices
public class CustomWebApplicationFactory<TProgram> : WebApplicationFactory<TProgram> where TProgram : class { protected override void ConfigureWebHost(IWebHostBuilder builder) { builder.ConfigureServices(services => { var dbContextDescriptor = services.SingleOrDefault( d => d.ServiceType == typeof(DbContextOptions<ApplicationDbContext>)); services.Remove(dbContextDescriptor); var dbConnectionDescriptor = services.SingleOrDefault( d => d.ServiceType == typeof(DbConnection)); services.Remove(dbConnectionDescriptor); // Create open SqliteConnection so EF won't automatically close it. services.AddSingleton<DbConnection>(container => { var connection = new SqliteConnection("DataSource=:memory:"); connection.Open(); return connection; }); services.AddDbContext<ApplicationDbContext>((container, options) => { var connection = container.GetRequiredService<DbConnection>(); options.UseSqlite(connection); }); }); builder.UseEnvironment("Development"); } }
Örnek uygulamadaki veritabanı tohumlama yöntemi tarafından
InitializeDbForTests
gerçekleştirilir. Yöntemi, Tümleştirme testleri örneği: Test uygulaması kuruluşu bölümünde açıklanmıştır.SUT'nin veritabanı bağlamı içinde
Program.cs
kaydedilir. Test uygulamasınınbuilder.ConfigureServices
geri çağırması, uygulamanınProgram.cs
kodu yürütüldükten sonra yürütülür. Testlerde uygulamanın veritabanından farklı bir veritabanı kullanmak için, uygulamanın veritabanı bağlamı içindebuilder.ConfigureServices
değiştirilmelidir.Örnek uygulama, veritabanı bağlamı için hizmet tanımlayıcısını bulur ve hizmet kaydını kaldırmak için tanımlayıcıyı kullanır. Ardından fabrika, testler için bellek içi veritabanı kullanan yeni
ApplicationDbContext
bir ekliyor..Farklı bir veritabanına bağlanmak için öğesini
DbConnection
değiştirin. SQL Server test veritabanını kullanmak için:
- Proje dosyasındaKi
Microsoft.EntityFrameworkCore.SqlServer
NuGet paketine başvurun. UseInMemoryDatabase
çağrısı yapın.
Test sınıflarında özel
CustomWebApplicationFactory
öğesini kullanın. Aşağıdaki örnekte sınıfındakiIndexPageTests
fabrika kullanılır:public class IndexPageTests : IClassFixture<CustomWebApplicationFactory<Program>> { private readonly HttpClient _client; private readonly CustomWebApplicationFactory<Program> _factory; public IndexPageTests( CustomWebApplicationFactory<Program> factory) { _factory = factory; _client = factory.CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false }); }
Örnek uygulamanın istemcisi, aşağıdaki yeniden yönlendirmelerin
HttpClient
engellenmesi için yapılandırılır. Sahte kimlik doğrulaması bölümünde daha sonra açıklandığı gibi bu, testlerin uygulamanın ilk yanıtının sonucunu denetlemesine izin verir. İlk yanıt, bu testlerin çoğunda üst bilgi içeren birLocation
yeniden yönlendirmedir.Tipik bir test, isteği ve yanıtı işlemek için ve yardımcı yöntemlerini kullanır
HttpClient
:[Fact] public async Task Post_DeleteAllMessagesHandler_ReturnsRedirectToRoot() { // Arrange var defaultPage = await _client.GetAsync("/"); var content = await HtmlHelpers.GetDocumentAsync(defaultPage); //Act var response = await _client.SendAsync( (IHtmlFormElement)content.QuerySelector("form[id='messages']"), (IHtmlButtonElement)content.QuerySelector("button[id='deleteAllBtn']")); // Assert Assert.Equal(HttpStatusCode.OK, defaultPage.StatusCode); Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); Assert.Equal("/", response.Headers.Location.OriginalString); }
SUT'ye yapılan herhangi bir POST isteği, uygulamanın veri koruma önleme sistemi tarafından otomatik olarak yapılan kötü amaçlı yazılımdan koruma denetimini karşılamalıdır. Testin POST isteğini düzenlemek için test uygulamasının şunları yapması gerekir:
- Sayfa için bir istekte bulun.
- Antiforgery'yi cookie ayrıştırın ve yanıttan doğrulama belirteci isteyin.
- POST isteğini sahteciliğe cookie karşı koruma ve istek doğrulama belirteci ile gerçekleştirin.
Örnek SendAsync
uygulamadaki GetDocumentAsync
yardımcı uzantı yöntemleri (Helpers/HttpClientExtensions.cs
) ve yardımcı yöntemi (Helpers/HtmlHelpers.cs
), aşağıdaki yöntemlerle antiforgery denetimini işlemek için AngleSharp ayrıştırıcısını kullanır:
GetDocumentAsync
: alır HttpResponseMessage ve döndürürIHtmlDocument
.GetDocumentAsync
, özgünHttpResponseMessage
öğesini temel alan bir sanal yanıt hazırlayan bir fabrika kullanır. Daha fazla bilgi için AngleSharp belgelerine bakın.SendAsync
oluşturma HttpRequestMessage ve SUT'ye istek gönderme çağrısı SendAsync(HttpRequestMessage) için uzantı yöntemleriHttpClient
. HTML formunu (IHtmlFormElement
) ve aşağıdakileri kabul etmek içinSendAsync
aşırı yüklemeler:- Formun Gönder düğmesi (
IHtmlElement
) - Form değerleri koleksiyonu (
IEnumerable<KeyValuePair<string, string>>
) - Gönder düğmesi (
IHtmlElement
) ve form değerleri (IEnumerable<KeyValuePair<string, string>>
)
- Formun Gönder düğmesi (
AngleSharp, bu makalede ve örnek uygulamada gösterim amacıyla kullanılan bir üçüncü taraf ayrıştırma kitaplığıdır. AngleSharp, ASP.NET Core uygulamalarının tümleştirme testi için desteklenmez veya gerekli değildir. Html Çeviklik Paketi (HAP) gibi diğer ayrıştırıcılar kullanılabilir. Bir diğer yaklaşım da, sahteciliğe karşı koruma sisteminin istek doğrulama belirtecini ve kötü amaçlı yazılımdan korumayı doğrudan işlemek için kod yazmaktır cookie . Daha fazla bilgi için bu makaledeki AngleSharp vs Application Parts
antiforgery denetimleri konusuna bakın.
EF-Core bellek içi veritabanı sağlayıcısı sınırlı ve temel test için kullanılabilir, ancak bellek içi test için önerilen seçenek SQLite sağlayıcısıdır.
Bkz . Başlangıç'ı başlangıç filtreleri ile genişletme. Bu, bir test özel hizmet veya ara yazılım gerektirdiğinde yararlı olan kullanarak IStartupFilterara yazılımı yapılandırmayı gösterir.
WithWebHostBuilder ile istemciyi özelleştirme
Bir test yönteminde ek yapılandırma gerektiğinde, WithWebHostBuilder yapılandırma tarafından daha da özelleştirilmiş bir ile yeni WebApplicationFactory
bir IWebHostBuilder oluşturur.
Örnek kod, yapılandırılmış hizmetleri test saptamalarıyla değiştirmek için çağırırWithWebHostBuilder
. Daha fazla bilgi ve örnek kullanım için bu makaledeki Sahte hizmetler ekleme bölümüne bakın.
Post_DeleteMessageHandler_ReturnsRedirectToRoot
Örnek uygulamanın test yöntemi, kullanımını WithWebHostBuilder
gösterir. Bu test, SUT'da form gönderimini tetikleyerek veritabanında bir kayıt silme işlemi gerçekleştirir.
sınıfındaki IndexPageTests
başka bir test veritabanındaki tüm kayıtları silen ve yönteminden önce Post_DeleteMessageHandler_ReturnsRedirectToRoot
çalıştırabilen bir işlem gerçekleştirdiğinden, SUT'nin silmesi için bir kaydın mevcut olduğundan emin olmak için bu test yönteminde veritabanı yeniden görüntülenir. SUT'daki formun ilk sil düğmesinin messages
seçilmesi, SUT isteğinde benzetim yapılır:
[Fact]
public async Task Post_DeleteMessageHandler_ReturnsRedirectToRoot()
{
// Arrange
using (var scope = _factory.Services.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<ApplicationDbContext>();
Utilities.ReinitializeDbForTests(db);
}
var defaultPage = await _client.GetAsync("/");
var content = await HtmlHelpers.GetDocumentAsync(defaultPage);
//Act
var response = await _client.SendAsync(
(IHtmlFormElement)content.QuerySelector("form[id='messages']"),
(IHtmlButtonElement)content.QuerySelector("form[id='messages']")
.QuerySelector("div[class='panel-body']")
.QuerySelector("button"));
// Assert
Assert.Equal(HttpStatusCode.OK, defaultPage.StatusCode);
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
Assert.Equal("/", response.Headers.Location.OriginalString);
}
İstemci seçenekleri
WebApplicationFactoryClientOptions Örnek oluştururken HttpClient
varsayılanlar ve kullanılabilir seçenekler için sayfaya bakın.
sınıfını WebApplicationFactoryClientOptions
oluşturun ve yöntemine CreateClient() geçirin:
public class IndexPageTests :
IClassFixture<CustomWebApplicationFactory<Program>>
{
private readonly HttpClient _client;
private readonly CustomWebApplicationFactory<Program>
_factory;
public IndexPageTests(
CustomWebApplicationFactory<Program> factory)
{
_factory = factory;
_client = factory.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
}
NOT: HTTPS Yeniden Yönlendirme Ara Yazılımı kullanılırken günlüklerde HTTPS yeniden yönlendirme uyarılarından kaçınmak için BaseAddress = new Uri("https://localhost")
Sahte hizmetler ekleme
Hizmetler, konak oluşturucusunda çağrısı ConfigureTestServices yapılan bir testte geçersiz kılınabilir. Geçersiz kılınan hizmetlerin kapsamını testin kendisi olarak tanımlamak için yöntemi bir WithWebHostBuilder konak oluşturucu almak için kullanılır. Bu durum aşağıdaki testlerde görülebilir:
- Get_QuoteService_ProvidesQuoteInPage
- Get_GithubProfilePageCanGetAGithubUser
- Get_SecurePageIsReturnedForAnAuthenticatedUser
Örnek SUT, teklif döndüren kapsamlı bir hizmet içerir. Teklif, Dizin sayfası istendiğinde Dizin sayfasındaki gizli bir alana eklenir.
Services/IQuoteService.cs
:
public interface IQuoteService
{
Task<string> GenerateQuote();
}
Services/QuoteService.cs
:
// Quote ©1975 BBC: The Doctor (Tom Baker); Dr. Who: Planet of Evil
// https://www.bbc.co.uk/programmes/p00pyrx6
public class QuoteService : IQuoteService
{
public Task<string> GenerateQuote()
{
return Task.FromResult<string>(
"Come on, Sarah. We've an appointment in London, " +
"and we're already 30,000 years late.");
}
}
Program.cs
:
services.AddScoped<IQuoteService, QuoteService>();
Pages/Index.cshtml.cs
:
public class IndexModel : PageModel
{
private readonly ApplicationDbContext _db;
private readonly IQuoteService _quoteService;
public IndexModel(ApplicationDbContext db, IQuoteService quoteService)
{
_db = db;
_quoteService = quoteService;
}
[BindProperty]
public Message Message { get; set; }
public IList<Message> Messages { get; private set; }
[TempData]
public string MessageAnalysisResult { get; set; }
public string Quote { get; private set; }
public async Task OnGetAsync()
{
Messages = await _db.GetMessagesAsync();
Quote = await _quoteService.GenerateQuote();
}
Pages/Index.cs
:
<input id="quote" type="hidden" value="@Model.Quote">
SUT uygulaması çalıştırıldığında aşağıdaki işaretleme oluşturulur:
<input id="quote" type="hidden" value="Come on, Sarah. We've an appointment in
London, and we're already 30,000 years late.">
Tümleştirme testinde hizmeti ve teklif eklemeyi test etmek için test tarafından SUT'ye sahte hizmet eklenir. Sahte hizmet, uygulamanın yerine test uygulaması QuoteService
tarafından sağlanan ve adlı TestQuoteService
bir hizmettir:
IntegrationTests.IndexPageTests.cs
:
// Quote ©1975 BBC: The Doctor (Tom Baker); Pyramids of Mars
// https://www.bbc.co.uk/programmes/p00pys55
public class TestQuoteService : IQuoteService
{
public Task<string> GenerateQuote()
{
return Task.FromResult(
"Something's interfering with time, Mr. Scarman, " +
"and time is my business.");
}
}
ConfigureTestServices
çağrılır ve kapsamı belirlenmiş hizmet kaydedilir:
[Fact]
public async Task Get_QuoteService_ProvidesQuoteInPage()
{
// Arrange
var client = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.AddScoped<IQuoteService, TestQuoteService>();
});
})
.CreateClient();
//Act
var defaultPage = await client.GetAsync("/");
var content = await HtmlHelpers.GetDocumentAsync(defaultPage);
var quoteElement = content.QuerySelector("#quote");
// Assert
Assert.Equal("Something's interfering with time, Mr. Scarman, " +
"and time is my business.", quoteElement.Attributes["value"].Value);
}
Testin yürütülmesi sırasında oluşturulan işaretleme, tarafından TestQuoteService
sağlanan tırnak metnini yansıtır, böylece onay geçer:
<input id="quote" type="hidden" value="Something's interfering with time,
Mr. Scarman, and time is my business.">
Sahte kimlik doğrulaması
Sınıfındaki AuthTests
testler güvenli bir uç nokta olup olmadığını denetler:
- Kimliği doğrulanmamış bir kullanıcıyı uygulamanın oturum açma sayfasına yönlendirir.
- Kimliği doğrulanmış bir kullanıcının içeriğini döndürür.
SUT'de sayfa, /SecurePage
sayfaya uygulamak için bir AuthorizePage AuthorizeFilter kural kullanır. Daha fazla bilgi için bkz Razor . Sayfa yetkilendirme kuralları.
services.AddRazorPages(options =>
{
options.Conventions.AuthorizePage("/SecurePage");
});
Testte Get_SecurePageRedirectsAnUnauthenticatedUser
, ayarı WebApplicationFactoryClientOptions olarak ayarlanarak AllowAutoRedirect yeniden yönlendirmelere izin vermemeye false
ayarlanmıştır:
[Fact]
public async Task Get_SecurePageRedirectsAnUnauthenticatedUser()
{
// Arrange
var client = _factory.CreateClient(
new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
// Act
var response = await client.GetAsync("/SecurePage");
// Assert
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
Assert.StartsWith("http://localhost/Identity/Account/Login",
response.Headers.Location.OriginalString);
}
İstemcinin yeniden yönlendirmeyi izlemesine izin vermeyerek aşağıdaki denetimler yapılabilir:
- SUT tarafından döndürülen durum kodu, oturum açma sayfasına yeniden yönlendirmeden sonraki son durum koduna değil beklenen HttpStatusCode.Redirect sonucta göre denetlenebilir. Bu, olacaktır HttpStatusCode.OK.
- Yanıt
Location
üst bilgilerindeki üst bilgi değeri, üst bilginin bulunmayacağı son oturum açma sayfası yanıtıyla değil ileLocation
başladığınıhttp://localhost/Identity/Account/Login
onaylamak için denetlendi.
Test uygulaması, kimlik doğrulaması ve yetkilendirme özelliklerini test etmek için bir AuthenticationHandler<TOptions> ConfigureTestServices ile dalga geçebilir. En düşük senaryo bir AuthenticateResult.Successdöndürür:
public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public TestAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var claims = new[] { new Claim(ClaimTypes.Name, "Test user") };
var identity = new ClaimsIdentity(claims, "Test");
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, "TestScheme");
var result = AuthenticateResult.Success(ticket);
return Task.FromResult(result);
}
}
TestAuthHandler
, kimlik doğrulama düzeni için kaydedildiği yere AddAuthentication
ayarlandığında TestScheme
kullanıcının kimliğini doğrulamak için ConfigureTestServices
çağrılır. Düzenin uygulamanızın TestScheme
beklediği düzenle eşleşmesi önemlidir. Aksi takdirde kimlik doğrulaması çalışmaz.
[Fact]
public async Task Get_SecurePageIsReturnedForAnAuthenticatedUser()
{
// Arrange
var client = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.AddAuthentication(defaultScheme: "TestScheme")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(
"TestScheme", options => { });
});
})
.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false,
});
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(scheme: "TestScheme");
//Act
var response = await client.GetAsync("/SecurePage");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
hakkında WebApplicationFactoryClientOptions
daha fazla bilgi için İstemci seçenekleri bölümüne bakın.
Kimlik doğrulaması ara yazılımı için temel testler
Kimlik doğrulama ara yazılımının temel testleri için bu GitHub deposuna bakın. Test senaryosuna özgü bir test sunucusu içerir.
Ortamı ayarlama
Ortamı özel uygulama fabrikasında ayarlayın:
public class CustomWebApplicationFactory<TProgram>
: WebApplicationFactory<TProgram> where TProgram : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
var dbContextDescriptor = services.SingleOrDefault(
d => d.ServiceType ==
typeof(DbContextOptions<ApplicationDbContext>));
services.Remove(dbContextDescriptor);
var dbConnectionDescriptor = services.SingleOrDefault(
d => d.ServiceType ==
typeof(DbConnection));
services.Remove(dbConnectionDescriptor);
// Create open SqliteConnection so EF won't automatically close it.
services.AddSingleton<DbConnection>(container =>
{
var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
return connection;
});
services.AddDbContext<ApplicationDbContext>((container, options) =>
{
var connection = container.GetRequiredService<DbConnection>();
options.UseSqlite(connection);
});
});
builder.UseEnvironment("Development");
}
}
Test altyapısı uygulama içeriği kök yolunu nasıl çıkarsar?
Oluşturucu, WebApplicationFactory
derlemeye eşit TEntryPoint
bir WebApplicationFactoryContentRootAttribute anahtara sahip tümleştirme testlerini içeren derlemede öğesini arayarak uygulama içeriği kök yolunu çıkarsarSystem.Reflection.Assembly.FullName
. Doğru anahtara sahip bir özniteliğin bulunamazsa, WebApplicationFactory
çözüm dosyasını aramaya (.sln) geri döner ve derleme adını çözüm dizinine ekler TEntryPoint
. Uygulama kök dizini (içerik kök yolu), görünümleri ve içerik dosyalarını bulmak için kullanılır.
Gölge kopyalamayı devre dışı bırakma
Gölge kopyalama, testlerin çıkış dizininden farklı bir dizinde yürütülmesine neden olur. Testleriniz ile ilgili Assembly.Location
dosyaları yüklemeye bağlıysa ve sorunlarla karşılaşıyorsanız, gölge kopyalamayı devre dışı bırakmanız gerekebilir.
xUnit kullanırken gölge kopyalamayı devre dışı bırakmak için test projesi dizininizde doğru yapılandırma ayarıyla bir xunit.runner.json
dosya oluşturun:
{
"shadowCopy": false
}
Nesnelerin atılması
Uygulamanın testleri IClassFixture
yürütüldükten TestServer ve HttpClient xUnit WebApplicationFactory
tarafından atıldığında atılır. Geliştirici tarafından örneği oluşturulmuş nesneler elden çıkarılma gerektiriyorsa, bunları IClassFixture
uygulamada atın. Daha fazla bilgi için bkz . Dispose yöntemi uygulama.
Tümleştirme testleri örneği
Örnek uygulama iki uygulamadan oluşur:
Uygulama | Proje dizini | Açıklama |
---|---|---|
İleti uygulaması (SUT) | src/RazorPagesProject |
Kullanıcının bir ileti eklemesine, silmesine, tümünü silmesine ve iletileri analiz etmesine izin verir. |
Test uygulaması | tests/RazorPagesProject.Tests |
SUT'yi tümleştirme 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, dizindeki bir komut isteminde aşağıdaki komutu yürütürtests/RazorPagesProject.Tests
:
dotnet test
İleti uygulaması (SUT) kuruluşu
SUT, 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 (ileti başına ortalama sözcükler) denetlemek için bir kullanıcı arabirimi ve sayfa modeli yöntemleri sağlar. - 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
() bir veri erişim katmanı (Data/AppDbContext.cs
DAL) içerir. - Uygulama başlangıcında veritabanı boşsa, ileti deposu üç iletiyle başlatılır.
- Uygulama yalnızca kimliği doğrulanmış bir
/SecurePage
kullanıcı tarafından erişilebilen bir içerir.
† InMemory ile test etme ef makalesi, 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.
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 Test denetleyicisi mantığı (örnek, depo düzenini uygular).
Uygulama kuruluşunu test et
Test uygulaması, dizinin içindeki tests/RazorPagesProject.Tests
bir konsol uygulamasıdır.
Uygulama dizinini test et | Açıklama |
---|---|
AuthTests |
Aşağıdakiler için test yöntemlerini içerir:
|
BasicTests |
Yönlendirme ve içerik türü için bir test yöntemi içerir. |
IntegrationTests |
Özel WebApplicationFactory sınıf kullanarak Dizin sayfasının tümleştirme testlerini içerir. |
Helpers/Utilities |
|
Test çerçevesi xUnit'tir. Tümleştirme testleri, öğesini içeren TestServerkullanılarak Microsoft.AspNetCore.TestHostyapılır. Microsoft.AspNetCore.Mvc.Testing
Paket test ana bilgisayarını ve test sunucusunu yapılandırmak için kullanıldığından TestHost
ve TestServer
paketleri, test uygulamasının proje dosyasında veya test uygulamasındaki geliştirici yapılandırmasında doğrudan paket başvuruları gerektirmez.
Tümleştirme testleri genellikle test yürütmeden önce veritabanında küçük bir veri kümesi gerektirir. Örneğin, silme testi veritabanı kaydı silme işlemini çağırır, bu nedenle silme isteğinin başarılı olması için veritabanında en az bir kayıt olmalıdır.
Örnek uygulama, testleri yürütürken kullanabileceği üç iletiyle Utilities.cs
veritabanının çekirdeğini oluşturur:
public static void InitializeDbForTests(ApplicationDbContext db)
{
db.Messages.AddRange(GetSeedingMessages());
db.SaveChanges();
}
public static void ReinitializeDbForTests(ApplicationDbContext db)
{
db.Messages.RemoveRange(db.Messages);
InitializeDbForTests(db);
}
public static List<Message> GetSeedingMessages()
{
return new List<Message>()
{
new Message(){ Text = "TEST RECORD: You're standing on my scarf." },
new Message(){ Text = "TEST RECORD: Would you like a jelly baby?" },
new Message(){ Text = "TEST RECORD: To the rational mind, " +
"nothing is inexplicable; only unexplained." }
};
}
SUT'nin veritabanı bağlamı içinde Program.cs
kaydedilir. Test uygulamasının builder.ConfigureServices
geri çağırması, uygulamanın Program.cs
kodu yürütüldükten sonra yürütülür. Testlerde farklı bir veritabanı kullanmak için uygulamanın veritabanı bağlamı içinde builder.ConfigureServices
değiştirilmelidir. Daha fazla bilgi için WebApplicationFactory'yi Özelleştirme bölümüne bakın.
Ek kaynaklar
ASP.NET Core