ASP.NET Core tümleştirme testleri

, Javier Calvarro Nelson, Steve Smithve Jos van der til

Tümleştirme sınamaları, uygulamanın bileşenlerinin veritabanı, dosya sistemi ve ağ gibi destekleyici altyapısını içeren bir düzeyde doğru şekilde çalışmasını güvence altına alır. ASP.NET Core, test web ana bilgisayarı ve bellek içi test sunucusu olan bir birim testi çerçevesini kullanarak tümleştirme testlerini destekler.

Bu konuda, birim testlerinin temel bir şekilde anlaşıldığı varsayılır. Test kavramları hakkında bilgi sahibi değilseniz, .NET Core 'Da birim testine ve .NET Standard konusuna ve bağlı içeriğine bakın.

Örnek kodu görüntüleme veya indirme (nasıl indirileceği)

Örnek uygulama bir Razor Sayfalar uygulamasıdır ve sayfaların temel olarak anlaşıldığını varsayar Razor . Sayfalarla alışkın değilseniz Razor , aşağıdaki konulara bakın:

Not

Maça 'Ları test etmek için, bir tarayıcıyı otomatikleştirebilen .net Için playwrightgibi bir araç öneririz.

Tümleştirme testlerine giriş

Tümleştirme testleri, bir uygulamanın bileşenlerini birim testlerindendaha geniş bir düzeyde değerlendirir. Birim testleri, ayrı 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 beklenen bir sonuç üretmek için birlikte çalıştığını ve muhtemelen bir isteği tam olarak işlemek için gereken her bileşeni de dahil olduğunu onaylar.

Bu geniş testler, uygulamanın altyapısını ve tüm çatısını test etmek için kullanılır, genellikle aşağıdaki bileşenler dahil:

  • Veritabanı
  • Dosya sistemi
  • Ağ gereçleri
  • İstek-yanıt işlem hattı

Birim testleri, altyapı bileşenlerinin yerine, Fakes veya sahte nesneler olarak bilinen fabriccomponents bileşenlerini 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 gerektir.
  • Çalıştırmak 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 edilebilir ise, birim testini seçin.

Tümleştirme testlerinin tartışmalarında, test edilen proje genellikle test altındaki sistem veya kısa IÇIN "sut" olarak adlandırılır. bu konu başlığı altında, sınanan ASP.NET Core uygulamasına başvurmak için "sut" kullanılır.

İpucu

Veritabanları ve dosya sistemleriyle ilgili her olası veri ve dosya erişimi için tümleştirme testleri yazma. Bir uygulamadaki kaç yerde veritabanlarıyla ve dosya sistemleriyle etkileşime girdiğinize bakılmaksızın, bir dizi Read, Write, Update ve DELETE tümleştirme testi, genellikle veritabanı ve dosya sistemi bileşenlerinin yeterli şekilde test edilmesine sahip olur. Bu bileşenlerle etkileşime geçen Yöntem mantığının rutin testleri için birim testleri kullanın. Birim testlerinde, altyapı kullanımı ve moizler 'in kullanılması daha hızlı test yürütmesiyle sonuçlanır.

ASP.NET Core tümleştirme testleri

ASP.NET Core tümleştirme testleri şunları gerektirir:

  • Testleri içermesi ve yürütmek için bir test projesi kullanılır. Test projesinin SUT 'a bir 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.
  • Test Çalıştırıcısı, testleri yürütmek ve test sonuçlarını raporlamak için kullanılır.

Tümleştirme testleri, olağan düzenleme, hareket ve onaylama testi adımlarını içeren bir olay dizisini izler:

  1. SUT 'un web ana bilgisayarı yapılandırıldı.
  2. İstekleri uygulamaya göndermek için bir test sunucusu istemcisi oluşturulur.
  3. Testi Düzenle adımı yürütülür: test uygulaması bir istek hazırlar.
  4. Davran test adımı yürütülür: istemci, isteği gönderir ve yanıtını alır.
  5. Onaylama testi adımı yürütülür: Gerçek yanıt, beklenen bir yanıta bağlı olarak başarılı veya başarısız olarak onaylanır.
  6. İşlem, tüm testler yürütülene kadar devam eder.
  7. Test sonuçları raporlanır.

Genellikle, test Web ana bilgisayarı, test çalıştırmaları için uygulamanın normal web ana bilgisayarında farklı şekilde yapılandırılır. Örneğin, testler için farklı bir veritabanı veya farklı uygulama ayarları kullanılıyor olabilir.

Test Web Konağı ve bellek içi test sunucusu () gibi altyapı bileşenleri, TestServer 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.

Microsoft.AspNetCore.Mvc.TestingPaket aşağıdaki görevleri gerçekleştirir:

  • Bağımlılıklar dosyasını ( .deps ) SUT 'den test projesinin bin dizinine kopyalar.
  • , Testler yürütüldüğünde statik dosya ve sayfa/görünümlerin bulunması için içerik kökünü sut 'nin proje köküne ayarlar.
  • , İle SUT önyükleyiciyi kolaylaştırmak için Webapplicationfactory sınıfını sağlar TestServer .

Birim testi belgeleri bir test projesi ve Test Çalıştırıcısı ayarlamayı ve testlerin ve test sınıflarının nasıl belirleneceğini gösteren testlerin ve önerilerin nasıl çalıştırılacağını gösteren ayrıntılı yönergelerle birlikte açıklanır.

Not

Bir uygulama için test projesi oluştururken, birim testlerini tümleştirme testlerinden farklı projelere ayırın. Bu, altyapı testi bileşenlerinin birim testlerine yanlışlıkla dahil olmamasını sağlamaya yardımcı olur. Birim ve tümleştirme testlerinin ayrımı, hangi test kümesinin çalıştırılmasına da izin verir.

Uygulamaların ve MVC uygulamalarının testleri için yapılandırma arasında neredeyse fark yoktur Razor . Tek fark testlerin adlandırılmasınlardır. Bir Razor Sayfalar uygulamasında sayfa uç noktalarının testleri genellikle sayfa modeli sınıfından sonra (örneğin, IndexPageTests Dizin sayfasına yönelik bileşen tümleştirmesini test etmek için) adlandırılır. MVC uygulamasında testler genellikle denetleyici sınıfları tarafından düzenlenir ve test ettikleri denetleyiciler (örneğin, HomeControllerTests denetleyicinin bileşen tümleştirmesini test etmek için) ile adlandırılır Home .

Test uygulaması önkoşulları

Test projesi şunları vermelidir:

Bu Önkoşullar örnek uygulamadagörülebilir. Dosyayı inceleyin tests/RazorPagesProject.Tests/RazorPagesProject.Tests.csproj . Örnek uygulama, xUnit test çerçevesini ve anglesharp Parser kitaplığını kullanır, bu nedenle örnek uygulama de şu şekilde başvurur:

xunit.runner.visualstudioSürüm 2.4.2 sections veya üstünü kullanan uygulamalarda, test projesinin pakete başvurması gerekir Microsoft.NET.Test.Sdk .

Entity Framework Core, testlerde de kullanılır. Uygulama başvuru:

SUT ortamı

SUT ortamı ayarlanmamışsa, ortam varsayılan olarak geliştirme olur.

Varsayılan WebApplicationFactory ile temel testler

WebApplicationFactory<TEntryPoint> , TestServer tümleştirme testleri için oluşturmak için kullanılır. TEntryPoint , genellikle sınıfının, SUT 'ın giriş noktası sınıfıdır Startup .

Test sınıfları sınıfı IClassFixture testlerin içerdiğini göstermek ve sınıftaki testler arasında paylaşılan nesne örnekleri sağlamak için bir sınıf armatürü arabirimi () uygular.

Aşağıdaki test sınıfı, BasicTests SUT 'yi önyüklemek WebApplicationFactory ve bir test yöntemi sağlamak için öğesini kullanır HttpClient Get_EndpointsReturnSuccessAndCorrectContentType . Yöntemi, yanıt durum kodunun başarılı olup olmadığını denetler (200-299 aralığındaki durum kodları) ve Content-Type üst bilgi text/html; charset=utf-8 birçok uygulama sayfasına yöneliktir.

CreateClientHttpClientotomatik olarak yeniden yönlendirmeleri ve tutamaçları izleyen bir örneği oluşturur cookie .

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, cookie GDPR onay ilkesi etkinleştirildiğinde, gerekli olmayan s istekler arasında korunmaz. cookieTempData sağlayıcısı tarafından kullanılanlar gibi, gerekli olmayan öğeleri korumak için bunları testlerinizde gerekli olarak işaretleyin. Gerekli olarak işaretlemek için gereken yönergeler için cookie bkz. temel cookie .

WebApplicationFactory 'yi özelleştirme

Web ana bilgisayar yapılandırması, öğesinden devralarak WebApplicationFactory bir veya daha fazla özel fabrika oluşturmak için test sınıflarından bağımsız olarak oluşturulabilir:

  1. Devralma WebApplicationFactory ve geçersiz kılma ConfigureWebHost . , IWebHostBuilder İle hizmet koleksiyonu yapılandırmasına izin verir ConfigureServices :

    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ı dengeli dağıtımı, yöntemi tarafından gerçekleştirilir InitializeDbForTests . Yöntemi, tümleştirme testleri örneği: test uygulaması kuruluşu bölümünde açıklanmaktadır.

    SUT 'un veritabanı bağlamı Startup.ConfigureServices yöntemine kaydedilir. Test uygulamasının builder.ConfigureServices geri çağırması, uygulamanın kodu yürütüldükten sonra yürütülür Startup.ConfigureServices . yürütme sırası, genel ana bilgisayar için ASP.NET Core 3,0 sürümüne sahip bir son değişiklikten oluşur. Uygulamanın veritabanından farklı testler için farklı bir veritabanı kullanmak istiyorsanız, uygulamanın veritabanı bağlamı içinde değiştirilmelidir builder.ConfigureServices .

    Hala Web ana bilgisayarınıkullanan sımlar için, test uygulamasının builder.ConfigureServices geri çağırması sut kodundan önce yürütülür Startup.ConfigureServices . Test uygulamasının geri builder.ConfigureTestServices çağırması sonrasında 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 ApplicationDbContext bellek içinde veritabanı kullanan yeni bir veritabanı ekler.

    Bellek içinde 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ştirebilirsiniz. Bir test SQL Server kullanmak için:

    services.AddDbContext<ApplicationDbContext>((options, context) => 
    {
        context.UseSqlServer(
            Configuration.GetConnectionString("TestingDbConnectionString"));
    });
    
  2. Test sınıflarında CustomWebApplicationFactory özelini kullanın. Aşağıdaki örnek sınıfındaki fabrikayı IndexPageTests kullanı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önlendirmeleri HttpClient önlemek için yapılandırılmıştır. Daha sonra Sahte kimlik doğrulaması bölümünde anlatılacağı gibi bu, testlerin uygulamanın ilk yanıtının sonucu denetlemesine izin verir. İlk yanıt, bu testlerin çoğunda üst bilgisi olan bir yeniden Location yönlendirmedir.

  3. Tipik bir test, HttpClient isteği ve yanıtı işlemeye yardımcı ve yöntemlerini kullanır:

    [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'a yapılan post istekleri, uygulamanın veri koruma sahtecilik önleme sistemi tarafından otomatik olarak yapılan sahtecilik önleme denetimlerini karşılamalı. Testin POST isteğini düzenlemek için test uygulamasının:

  1. Sayfa için bir istekte bulunabilirsiniz.
  2. Kimlik sahteciliği ve istek cookie doğrulama belirteci yanıttan ayrıştır.
  3. Sahteciliği önleme ve istek doğrulama belirteci ile POST cookie isteğinde bulundurarak.

Örnek uygulamanın yardımcı uzantısı yöntemleri ( ) ve yardımcı yöntemi ( ) aşağıdaki yöntemlerle sahteciliği önleme denetimi için SendAsync Helpers/HttpClientExtensions.cs GetDocumentAsync Helpers/HtmlHelpers.cs AngleSharp ayrıştırıcısını kullanır:

  • GetDocumentAsync: alır HttpResponseMessage ve bir IHtmlDocument döndürür. GetDocumentAsync , özgün 'a göre bir sanal yanıt hazırlar bir fabrika HttpResponseMessage kullanır. Daha fazla bilgi için AngleSharp belgelerine bakın.
  • SendAsyncSUT'a istek göndermek için bir oluşturma ve çağrısı ) için HttpClient HttpRequestMessage uzantı yöntemleri. SendAsync(HttpRequestMessage HTML formunu SendAsync ( ) ve aşağıdakini kabul etmek için aşırı IHtmlFormElement 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>> )

Not

AngleSharp, bu konu başlığında ve örnek uygulamada tanıtım amacıyla kullanılan bir üçüncü taraf ayrıştırma kitaplığıdır. AngleSharp, uygulamaların tümleştirme testi için destek ASP.NET Core. Html Çeviklik Paketi (HAP) gibi diğer ayrıştırıcılar kullanılabilir. Bir diğer yaklaşım da, sahteci sistemin istek doğrulama belirteci ve sahtecilik önlemeyi doğrudan işlemek için kod cookie yazmaktır.

İstemciyi WithWebHostBuilder ile özelleştirme

Bir test yönteminde ek yapılandırma gerektiğinde, yapılandırma tarafından daha fazla özelleştirilmiş WithWebHostBuilder bir ile yeni bir WebApplicationFactory IWebHostBuilder oluşturur.

Örnek Post_DeleteMessageHandler_ReturnsRedirectToRoot uygulamanın test yöntemi kullanımını WithWebHostBuilder gösteriyor. Bu test, SUT'da form gönderimini tetikleerek veritabanında bir kayıt silme işlemi gerçekleştirir.

sınıfındaki başka bir test veritabanındaki tüm kayıtları silen ve yöntemden önce çalıştırılana bir işlem gerçekleştirdiği IndexPageTests için, SUT'un silebilir durumda olduğundan emin olmak için veritabanı bu test yönteminde yeniden Post_DeleteMessageHandler_ReturnsRedirectToRoot kullanılır. SUT'ta formun messages ilk sil düğmesinin seçimi, SUT'a yapılan istekte benzetimli olarak simülasyonu yapılan bir düğmedir:

[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 WebApplicationFactoryClientOptions oluşturulurken kullanılabilen varsayılan HttpClient değerler yer almaktadır.

Seçenek Açıklama Varsayılan
AllowAutoRedirect Örneklerin yeniden yönlendirme yanıtlarını otomatik HttpClient olarak izlemesi gerekip gerekip gerekmey olmadığını alır veya ayarlar. true
BaseAddress Örneklerin temel adresini alır HttpClient veya ayarlar. http://localhost
HandleCookies Örneklerin s'leri HttpClient işlemesi gerekip gerekip gerek olmadığını alır veya cookie 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 (varsayılan değerler kod örneğinde gösterilir) iletir:

// 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

Konak oluşturucuda çağrısıyla hizmetler bir ConfigureTestServices testte geçersiz kılınabilir. Sahte hizmetler ekleme için SUT'un yöntemine sahip Startup bir sınıfı Startup.ConfigureServices olması gerekir.

Örnek SUT, teklif döndüren kapsamlı bir hizmet içerir. Teklif, Dizin sayfası isten geldiğinde Dizin sayfasındaki gizli bir alana eklenmiş olur.

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ıkları zaman aşağıdaki işaretleme oluşturulur:

<input id="quote" type="hidden" value="Come on, Sarah. We&#x27;ve an appointment in 
    London, and we&#x27;re already 30,000 years late.">

Hizmeti ve teklif eklemeyi tümleştirme testinde test etmek için, test tarafından SUT'a sahte bir hizmet ekleme işlemi edilir. Sahte hizmet, uygulamanın yerine test QuoteService uygulaması tarafından sağlanan adlı bir hizmetle TestQuoteService değiştirir:

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 kapsamlı 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 üretilen işaretleme, tarafından sağlanan tırnak metnini yansıtarak onay TestQuoteService işlemi başarılı olur:

<input id="quote" type="hidden" value="Something&#x27;s interfering with time, 
    Mr. Scarman, and time is my business.">

Sahte kimlik doğrulaması

sınıfındaki AuthTests testlerde güvenli bir uç nokta olup değildir:

  • Kimliği doğrulanmamış bir kullanıcıyı uygulamanın Oturum Açma sayfasına yeniden yönlendirer.
  • Kimliği doğrulanmış bir kullanıcının içeriğini döndürür.

SUT'ta /SecurePage sayfa, sayfaya AuthorizePage bir uygulamak için bir kuralı AuthorizeFilter kullanır. Daha fazla bilgi için Razor bkz. Sayfa yetkilendirme kuralları.

services.AddRazorPages(options =>
{
    options.Conventions.AuthorizePage("/SecurePage");
});

Get_SecurePageRedirectsAnUnauthenticatedUserTestte, olarak WebApplicationFactoryClientOptions ayarlandırarak yeniden yönlendirmelere izinmayacak şekilde AllowAutoRedirect 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 izlemesini izin veserle, aşağıdaki denetimler gerçek olabilir:

  • SUT tarafından döndürülen durum kodu, Oturum Açma sayfasına yönlendirdikten sonra son durum kodu değil beklenen sonuçla denetlenir. Bu durum HttpStatusCode.Redirect HttpStatusCode.Ok olur.
  • Yanıt üst bilgisinde üst bilgi değeri, üst bilginin mevcut olmadığının son Oturum açma sayfası yanıtıyla değil, ile başladığı Location http://localhost/Identity/Account/Login Location onaylanır.

Test uygulaması, kimlik doğrulaması AuthenticationHandler<TOptions> ve yetkilendirme yönlerini test etmek için bir ile sahte ConfigureTestServices olabilir. En düşük senaryo bir AuthenticateResult.Success dö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 şeması için nereye kayıtlı olarak ayarlanırsa kullanıcının kimliğini doğrulamak Test için AddAuthentication çağrılır. ConfigureTestServices Şemanın, Test uygulamanın beklediğiniz şemayla 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 daha fazla bilgi WebApplicationFactoryClientOptions 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ı kullanmak üzere yapılandırılır. kullanırken SUT ortamını geçersiz kılmak IHostBuilder için:

  • Ortam ASPNETCORE_ENVIRONMENT değişkenlerini ayarlayın Staging (örneğin, , veya gibi başka bir özel Production Testing değer).
  • ön CreateHostBuilder ekli ortam değişkenlerini okumak için test uygulamasında geçersiz ASPNETCORE kılın.
protected override IHostBuilder CreateHostBuilder() =>
    base.CreateHostBuilder()
        .ConfigureHostConfiguration(
            config => config.AddEnvironmentVariables("ASPNETCORE"));

SUT Web Ana Bilgisayarı () IWebHostBuilder kullanıyorsa, geçersiz CreateWebHostBuilder kılın:

protected override IWebHostBuilder CreateWebHostBuilder() =>
    base.CreateWebHostBuilder().UseEnvironment("Testing");

Test altyapısının uygulama içeriği kök yolunu nasıl çıkartır?

Oluşturucu, derlemeye eşit bir anahtarla tümleştirme testlerini içeren derlemede bir arayarak uygulama içeriği WebApplicationFactory kök yolunu WebApplicationFactoryContentRootAttribute TEntryPoint System.Reflection.Assembly.FullName çıkartır. Doğru anahtara sahip bir özniteliğin bulunamıyorsa, bir çözüm dosyası aramaya geri döner WebApplicationFactory (.sln) ve derleme adını TEntryPoint çözüm dizinine ekler. Görünümleri ve içerik dosyalarını bulmak için uygulama kök dizini (içerik kök yolu) kullanılır.

Gölge kopyalamayı devre dışı bırakma

Gölge kopyalama, testlerin çıkış dizininden farklı bir dizinde yürütmesini sağlar. Testlerinizi göre dosyaları yükleme ve sorunlarla Assembly.Location karşılaşırsanız, gölge kopyalamayı devre dışı bırakmanız gerekir.

xUnit kullanırken gölge kopyalamayı devre dışı bırakmak için test projesi dizininize doğru yapılandırma xunit.runner.json ayarıyla bir dosya oluşturun:

{
  "shadowCopy": false
}

Nesnelerin atılması

Uygulamanın testleri IClassFixture yürütülür ve TestServer xUnit tarafından HttpClient atıldıktan sonra atılması WebApplicationFactory gerekir. Geliştirici tarafından örneği yapılan nesnelerin atılması gerekirse, bunları uygulamada IClassFixture atabilirsiniz. Daha fazla bilgi için bkz. Dispose yöntemi uygulama.

Tümleştirme testleri örneği

Örnek uygulama iki uygulamalardan oluşur:

Uygulama Proje dizini Açıklama
İleti uygulaması (SUT) src/RazorPagesProject Kullanıcının ileti ekleme, silme, tüm iletileri silme ve analiz etme olanaklarını sağlar.
Uygulamayı test edin tests/RazorPagesProject.Tests SUT test tümleştirmesi için kullanılır.

Testler, Visual Studiogıbı 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ün tests/RazorPagesProject.Tests :

dotnet test

İleti uygulaması (SUT) kuruluşu

SUT, Razor aşağıdaki özelliklere sahip bir sayfalar ileti sistemidir:

  • Uygulamanın (ve) dizin sayfası, Pages/Index.cshtml Pages/Index.cshtml.cs iletilerin eklenmesi, silinmesini ve analizini denetlemek IÇIN bir UI ve sayfa modeli yöntemleri sağlar (ileti başına ortalama sözcük).
  • Bir ileti, ( Message Data/Message.cs ) sınıfının iki özelliği ile açıklanmıştır: Id (anahtar) ve Text (ileti). TextÖzelliği gereklidir ve 200 karakterle sınırlıdır.
  • İletiler, Entity Framework bellek içi veritabanı† kullanılarak depolanır.
  • Uygulama, () veritabanı bağlamı sınıfında bir veri erişim katmanı (DAL) içeriyor AppDbContext Data/AppDbContext.cs .
  • Veritabanı uygulama başlangıcında boşsa, ileti deposu üç iletiyle başlatılır.
  • Uygulama /SecurePage yalnızca kimliği doğrulanmış bir kullanıcı tarafından erişilebilen bir içerir.

EF konusunda, InMemory Ile Test†, MSTest ile testler için bellek içi bir veritabanının nasıl kullanılacağını açıklar. Bu konu xUnit test çerçevesini kullanır. Farklı test çerçeveleri genelinde test kavramları ve test uygulamaları benzerdir ancak aynı değildir.

Uygulama, depo desenini kullanmıyor ve Iş birimi (UoW) düzenininetkin bir örneği olmamasına karşın, Razor Sayfalar bu geliştirme düzenlerini destekler. Daha fazla bilgi için bkz. altyapı Kalıcılık katmanını tasarlama ve Test denetleyicisi mantığı (örnek, depo modelini uygular).

Test uygulaması kuruluşu

Test uygulaması, dizin içindeki bir konsol uygulamasıdır tests/RazorPagesProject.Tests .

Uygulama dizinini test et Description
AuthTests İçin test yöntemleri içerir:
  • Güvenli bir sayfaya, kimliği doğrulanmamış bir kullanıcıyla erişme.
  • Bir sahte ile kimliği doğrulanmış bir kullanıcı tarafından güvenli bir sayfaya erişme AuthenticationHandler<TOptions> .
  • GitHub kullanıcı profili alma ve profilin kullanıcı oturum açmasını denetleme.
BasicTests Yönlendirme ve içerik türü için bir test yöntemi içerir.
IntegrationTests Özel sınıf kullanan dizin sayfası için tümleştirme testlerini içerir WebApplicationFactory .
Helpers/Utilities
  • Utilities.cs``InitializeDbForTestsveritabanını test verileriyle tohum için kullanılan yöntemi içerir.
  • HtmlHelpers.cs test yöntemleri tarafından kullanılmak üzere bir AngleSharp döndüren bir yöntem sağlar IHtmlDocument .
  • HttpClientExtensions.cs``SendAsyncisteklerini SUT 'e göndermek için için aşırı yüklemeler sağlayın.

Test çerçevesi xUnit' dir. Tümleştirme testleri, Microsoft.AspNetCore.TestHost öğesini içeren kullanılarak yürütülür TestServer . Paket, Microsoft.AspNetCore.Mvc.Testing Test ana bilgisayarı ve test sunucusunu yapılandırmak için kullanıldığından, TestHost ve paketleri test uygulamasındaki TestServer Proje dosyasında veya geliştirici yapılandırmasında doğrudan paket başvuruları gerektirmez.

Tümleştirme testleri genellikle veritabanında test yürütmeden önce küçük bir veri kümesi gerektirir. Örneğin, veritabanı kaydı silme için bir silme testi çağrılarında, silme isteğinin başarılı olması için veritabanının en az bir kaydı olmalıdır.

Örnek uygulama, Utilities.cs testlerin yürütülmeleri sırasında kullanabileceği üç iletiyle birlikte veritabanını kullanır:

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 'un veritabanı bağlamı Startup.ConfigureServices yöntemine kaydedilir. Test uygulamasının builder.ConfigureServices geri çağırması, uygulamanın kodu yürütüldükten sonra yürütülür Startup.ConfigureServices . Testler için farklı bir veritabanı kullanmak istiyorsanız, uygulamanın veritabanı bağlamı içinde değiştirilmelidir builder.ConfigureServices . Daha fazla bilgi için, WebApplicationFactory 'Yi özelleştirme bölümüne bakın.

Hala Web ana bilgisayarınıkullanan sımlar için, test uygulamasının builder.ConfigureServices geri çağırması sut kodundan önce yürütülür Startup.ConfigureServices . Test uygulamasının builder.ConfigureTestServices geri çağırması sonra yürütülür.

Ek kaynaklar