Integrační testy v ASP.NET Core
Od : Cevarro Proced, Steve Smitha Jos van der Til
Integrační testy zajišťují, aby komponenty aplikace správně fungovaly na úrovni, která zahrnuje podpůrnou infrastrukturu aplikace, jako je databáze, systém souborů a síť. ASP.NET Core podporuje integrační testy pomocí rozhraní pro testování částí s testovacím webovým hostitelem a serverem testů v paměti.
Toto téma předpokládá základní znalosti o testech jednotek. Pokud koncepty testů neznáme, podívejte se na téma Testování částí v .NET Core a .NET Standard a související obsah.
Zobrazení nebo stažení ukázkového kódu (stažení)
Ukázková aplikace je aplikace Pages a Razor předpokládá základní znalosti o Razor stránkách. Pokud stránky nevidíte, projděte Razor si následující témata:
Poznámka
Pro testování rozhraní SPA doporučujeme nástroj, například Playwright pro .NET,který dokáže automatizovat prohlížeč.
Úvod do integračních testů
Integrační testy vyhodnocují komponenty aplikace na širší úrovni než testy jednotek. Testy jednotek se používají k testování izolovaných softwarových komponent, jako jsou metody jednotlivých tříd. Integrační testy potvrzují, že dvě nebo více komponent aplikace spolupracují, aby se vytvářel očekávaný výsledek, a to včetně všech komponent požadovaných k úplnému zpracování požadavku.
Tyto širší testy se používají k testování infrastruktury a celé architektury aplikace, často včetně následujících komponent:
- databáze
- Systém souborů
- Síťová zařízení
- Kanál požadavek-odpověď
Testy jednotek místo komponent infrastruktury používají fabricované komponenty, označované jako napodobenny nebo napodobené objekty.
Na rozdíl od testů jednotek integrační testy:
- Použijte skutečné komponenty, které aplikace používá v produkčním prostředí.
- Vyžadovat další zpracování kódu a dat.
- Spuštění trvá delší dobu.
Proto omezte použití integračních testů na nejdůležitější scénáře infrastruktury. Pokud je možné chování testovat pomocí testu jednotek nebo integračního testu, zvolte test jednotek.
V diskuzích o integračních testech se testovaný projekt často nazývá System Under Test(Testovaný systém) nebo zkráceně "SUT". "SUT" se v tomto tématu používá k odkazování na testované ASP.NET Core aplikace.
Tip
Nepište integrační testy pro každou možnou permutaci dat a přístupu k souborům s databázemi a systémy souborů. Bez ohledu na to, kolik míst v aplikaci komunikuje s databázemi a systémy souborů, jsou integrační testy zaměřené na čtení, zápis, aktualizaci a odstranění obvykle schopné adekvátně testovat komponenty databáze a systému souborů. Testy jednotek použijte pro rutinní testy logiky metody, které komunikují s těmito komponentami. V testech jednotek je použití napodobeninou/napodobeninou infrastruktury výsledkem rychlejšího provádění testů.
ASP.NET Core integrační testy
Integrační testy v ASP.NET Core vyžadují následující:
- Projekt testů slouží k obsahují a spouští testy. Projekt testů obsahuje odkaz na SUT.
- Projekt testů vytvoří testovacího webového hostitele pro SUT a použije klienta testovacího serveru ke zpracování požadavků a odpovědí pomocí SUT.
- Ke spuštění testů a hlášení výsledků testů se používá spouštěče testů.
Integrační testy se prochývají posloupností událostí, které zahrnují obvyklé kroky Uspořádat, Jednat a Vyhodnocení testu:
- Je nakonfigurovaný webový hostitel SUT.
- Vytvoří se klient testovacího serveru pro odesílání požadavků do aplikace.
- Spustí se testovací krok Uspořádat: Testovací aplikace připraví požadavek.
- Spustí se testovací krok Act: Klient odešle požadavek a obdrží odpověď.
- Spustí se testovací krok Assert: Skutečná odpověď se na základě očekávané odpovědi ověří jako průchod nebo selhání.
- Proces pokračuje, dokud nejsou provedeny všechny testy.
- Výsledky testu jsou hlášeny.
Testovací webový hostitel je obvykle nakonfigurovaný jinak než normální webový hostitel aplikace pro testovací běhy. Pro testy se například může použít jiná databáze nebo jiná nastavení aplikace.
Komponenty infrastruktury, jako je testovací webový hostitel a testovací server v paměti ( ), poskytuje nebo spravuje TestServer balíček Microsoft.AspNetCore.Mvc.Testing. Použití tohoto balíčku zjednodušuje vytváření a spouštění testů.
Balíček Microsoft.AspNetCore.Mvc.Testing zpracovává následující úlohy:
- Zkopíruje soubor závislostí (
.deps) z SUT do adresáře testovacíhobinprojektu. - Nastaví kořenovou hodnotu obsahu na kořen projektu SUT tak, aby se při spuštění testů zjistily statické soubory a stránky nebo zobrazení.
- Poskytuje třídu WebApplicationFactory pro zjednodušení bootstrapování SUT pomocí
TestServer.
Dokumentace k testům jednotek popisuje, jak nastavit projekt testů a spouštěče testů, spolu s podrobnými pokyny ke spouštění testů a doporučení k pojmení testů a testovacích tříd.
Poznámka
Při vytváření projektu testů pro aplikaci oddělte testy jednotek od integračních testů do různých projektů. To pomáhá zajistit, že součásti testování infrastruktury nebudou nechtěně zahrnuty do testů jednotek. Oddělení testů jednotek a integračních testů také umožňuje řídit, která sada testů se spustí.
V podstatě není žádný rozdíl mezi konfigurací pro testy aplikací Pages a Razor aplikacemi MVC. Jediným rozdílem je, jak jsou testy pojmenovány. V aplikaci Pages jsou testy koncových bodů stránky obvykle pojmenovány podle třídy modelu stránky (například k otestování integrace komponent Razor IndexPageTests pro stránku Index). V aplikaci MVC jsou testy obvykle uspořádány podle tříd kontrolerů a pojmenovány podle kontrolerů, které testují (například k otestování integrace komponent HomeControllerTests Home kontroleru).
Požadavky testovací aplikace
Projekt testů musí:
- Odkazovat na
Microsoft.AspNetCore.Mvc.Testingbalíček. - Zadejte webovou sadu SDK v souboru projektu (
<Project Sdk="Microsoft.NET.Sdk.Web">).
Tyto požadavky si můžete zobrazit v ukázkové aplikaci. Zkontrolujte tests/RazorPagesProject.Tests/RazorPagesProject.Tests.csproj soubor . Ukázková aplikace používá testovací rozhraní xUnit a knihovnu analyzátoru AngleSharp, takže ukázková aplikace také odkazuje na:
V aplikacích, xunit.runner.visualstudio které používají verzi 2.4.2 nebo novější, musí projekt testování odkazovat na Microsoft.NET.Test.Sdk balíček.
Entity Framework Core se také používá v testech. Aplikace odkazuje na:
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCoreMicrosoft.AspNetCore.Identity.EntityFrameworkCoreMicrosoft.EntityFrameworkCoreMicrosoft.EntityFrameworkCore.InMemoryMicrosoft.EntityFrameworkCore.Tools
Prostředí SUT
Pokud prostředí SUT není nastavené, výchozí nastavení prostředí je Vývoj.
Základní testy s výchozí webovou aplikací WebApplicationFactory
WebApplicationFactory<TEntryPoint> se používá k vytvoření TestServer pro integrační testy. TEntryPoint je třída vstupních bodů SUT, obvykle Startup třída .
Testovací třídy implementují rozhraní pro správu tříd ( ), které označuje, že třída obsahuje testy a poskytuje instance sdílených IClassFixture objektů napříč testy ve třídě.
Následující testovací třída BasicTests používá metodu ke WebApplicationFactory spuštění SUT a k poskytnutí metody HttpClient testu Get_EndpointsReturnSuccessAndCorrectContentType . Metoda zkontroluje, jestli je stavový kód odpovědi úspěšný (stavové kódy v rozsahu 200–299) a jestli se hlavička nachází Content-Type text/html; charset=utf-8 na několika stránkách aplikace.
CreateClient vytvoří instanci , HttpClient která automaticky sleduje přesměrování a popisovače cookie s.
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());
}
}
Ve výchozím nastavení se při povolení zásad souhlasu GDPR nezachovají jiné než cookie nezbytné požadavky. Pokud chcete zachovat jiné než nezbytné vlastnosti, například ty, které používá zprostředkovatel TempData, označte je cookie v testech jako nezbytné. Pokyny k označení jako cookie nezbytné najdete v části Základní cookie s.
Přizpůsobení WebApplicationFactory
Konfiguraci webového hostitele je možné vytvořit nezávisle na testovacích třídách tak, že z třídy dědíte a vytvoříte jednu nebo WebApplicationFactory více vlastních továren:
Dědí z
WebApplicationFactorya přepíšeConfigureWebHost. umožňujeIWebHostBuilderkonfiguraci kolekce služby pomocí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); } } }); } }Dosytování databáze v ukázkové aplikaci se provádí
InitializeDbForTestspomocí metody . Metoda je popsaná v ukázce integračních testů: Organizace testovací aplikace.Kontext databáze SUT je zaregistrovaný ve své
Startup.ConfigureServicesmetodě. Zpětné volání testovací aplikace se spustí po spuštění kódubuilder.ConfigureServicesStartup.ConfigureServicesaplikace. Pořadí provádění je změna typu obecná změna s vydáním verze ASP.NET Core 3.0. Pokud chcete pro testy použít jinou databázi než databázi aplikace, je nutné nahradit kontext databáze aplikace vbuilder.ConfigureServices.U SUT, které stále používají webového hostitele,se zpětné volání testovací aplikace provádí před
builder.ConfigureServiceskódem SUT.Startup.ConfigureServicesZpětné volání testovací aplikacebuilder.ConfigureTestServicesje provedeno po.Ukázková aplikace vyhledá popisovač služby pro kontext databáze a použije popisovač k odebrání registrace služby. V dalším kroku továrna přidá novou
ApplicationDbContext, která pro testy používá databázi v paměti.Chcete-li se připojit k jiné databázi než databáze v paměti, změňte
UseInMemoryDatabasevolání pro připojení kontextu k jiné databázi. použití testovací databáze SQL Server:- odkázat na
Microsoft.EntityFrameworkCore.SqlServerbalíček NuGet v souboru projektu. - Volání
UseSqlServers připojovacím řetězcem k databázi.
services.AddDbContext<ApplicationDbContext>((options, context) => { context.UseSqlServer( Configuration.GetConnectionString("TestingDbConnectionString")); });- odkázat na
Použijte vlastní
CustomWebApplicationFactoryv testovacích třídách. Následující příklad používá objekt factory veIndexPageTeststřídě: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 }); }Klient ukázkové aplikace je nakonfigurován tak, aby zabránil
HttpClientnásledujícímu přesměrování. Jak je vysvětleno dále v části model ověřování , umožňuje testům kontrolovat výsledek první odpovědi aplikace. První odpověď je přesměrování v mnoha těchto testech sLocationhlavičkou.Typický test používá
HttpClientpomocné metody a ke zpracování žádosti a odpovědi:[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); }
Jakýkoli požadavek POST na SUT musí splňovat kontrolu proti padělání, kterou automaticky provádí systém ochrany dat proti padělání dataplikace. Aby bylo možné uspořádat požadavek POST testu, musí aplikace testů:
- Vytvořte požadavek na stránku.
- Analyzovat antipadělání cookie a žádat ověřovací token z odpovědi.
- Proveďte požadavek POST se žádostí o cookie ověření a vyžádat ověřovací token.
SendAsyncPomocné metody rozšíření ( Helpers/HttpClientExtensions.cs ) a GetDocumentAsync pomocná metoda ( Helpers/HtmlHelpers.cs ) v ukázkové aplikaci používají analyzátor AngleSharp ke zpracování kontroly proti padělání pomocí následujících metod:
GetDocumentAsync: PřijmeHttpResponseMessagea vrátíIHtmlDocument.GetDocumentAsyncpoužívá objekt pro vytváření, který připraví virtuální odpověď na základě origináluHttpResponseMessage. Další informace najdete v dokumentaci k AngleSharp.SendAsyncmetody rozšíření proHttpClientvytvořeníHttpRequestMessagea voláníSendAsync(HttpRequestMessage) k odeslání požadavků do SUT. Přetížení proSendAsyncpřijměte formulář HTML (IHtmlFormElement) a následující:- Tlačítko Odeslat formuláře (
IHtmlElement) - Kolekce hodnot formulářů (
IEnumerable<KeyValuePair<string, string>>) - Odeslat tlačítko (
IHtmlElement) a hodnoty formuláře (IEnumerable<KeyValuePair<string, string>>)
- Tlačítko Odeslat formuláře (
Poznámka
AngleSharp je knihovna analýzy třetí strany, která se používá pro demonstrační účely v tomto tématu a v ukázkové aplikaci. AngleSharp se nepodporuje nebo nevyžaduje pro testování integrace ASP.NET Corech aplikací. Lze použít jiné analyzátory, jako je například HTML flexibility Pack (HAP). Další možností je napsat kód pro zpracování tokenu pro ověření žádosti systému System a jeho padělání cookie .
Přizpůsobení klienta pomocí WithWebHostBuilder
V případě, že v rámci testovací metody je vyžadována další konfigurace, WithWebHostBuilder vytvoří nový WebApplicationFactory s objektem IWebHostBuilder , který je dále přizpůsoben konfigurací.
Post_DeleteMessageHandler_ReturnsRedirectToRootTestovací metoda ukázkové aplikace demonstruje použití WithWebHostBuilder . Tento test provede v databázi odstranění záznamu aktivací formuláře v SUT.
Vzhledem k tomu, že jiný test ve IndexPageTests třídě provádí operaci, která odstraní všechny záznamy v databázi a může běžet před Post_DeleteMessageHandler_ReturnsRedirectToRoot metodou, databáze je v této testovací metodě znovu osazena, aby se zajistilo, že SUT k odstranění bude přítomen záznam. Výběr prvního tlačítka odstranit messages ve formuláři v SUT se simuluje v požadavku na SUT:
[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);
}
Možnosti klienta
V následující tabulce jsou uvedeny výchozí hodnoty, WebApplicationFactoryClientOptions které jsou k dispozici při vytváření HttpClient instancí.
| Možnost | Popis | Výchozí |
|---|---|---|
AllowAutoRedirect |
Získá nebo nastaví, jestli se HttpClient mají instance automaticky sledovat prostřednictvím odpovědí přesměrování. |
true |
BaseAddress |
Získá nebo nastaví základní adresu HttpClient instancí. |
http://localhost |
HandleCookies |
Získá nebo nastaví, jestli se HttpClient mají zpracovat instance cookie . |
true |
MaxAutomaticRedirections |
Získá nebo nastaví maximální počet odpovědí přesměrování, které HttpClient by měly instance následovat. |
7 |
Vytvořte WebApplicationFactoryClientOptions třídu a předejte ji do CreateClient metody (výchozí hodnoty jsou uvedeny v příkladu kódu):
// 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);
Vložení makety služeb
Služby lze v rámci testu přepsat voláním ConfigureTestServices v Tvůrci hostitele. Pro vložení makety služeb musí mít SUT Startup třídu s Startup.ConfigureServices metodou.
Vzorový SUT obsahuje oborovou službu, která vrací citát. Nabídka je vložena do skrytého pole na stránce index, když je požadována stránka indexu.
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">
Při spuštění aplikace SUT se vygeneruje následující kód:
<input id="quote" type="hidden" value="Come on, Sarah. We've an appointment in
London, and we're already 30,000 years late.">
Chcete-li otestovat vkládání služby a uvozovek v rámci integračního testu, je do SUTu vložena přípravou služba. Napodobná služba nahradí aplikaci QuoteService službou poskytnutou testovací aplikací, která se nazývá TestQuoteService :
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 je volána a zaregistrována Oborová služba:
[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);
}
Označení vyprodukované během provádění testu odráží text citace, který je dodaný pomocí TestQuoteService , takže kontrolní výraz projde:
<input id="quote" type="hidden" value="Something's interfering with time,
Mr. Scarman, and time is my business.">
Modely ověřování
Testy ve AuthTests třídě zkontrolují zabezpečený koncový bod:
- Přesměruje neověřeného uživatele na přihlašovací stránku aplikace.
- Vrátí obsah pro ověřeného uživatele.
V SUT /SecurePage stránka používá AuthorizePage konvenci pro použití AuthorizeFilter na stránku. Další informace najdete v tématu Razor autorizační konvence pro stránky.
services.AddRazorPages(options =>
{
options.Conventions.AuthorizePage("/SecurePage");
});
V Get_SecurePageRedirectsAnUnauthenticatedUser testu WebApplicationFactoryClientOptions je nastavené na zakázat přesměrování nastavením AllowAutoRedirect na false :
[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);
}
Když klientovi zakážete postup přesměrování, můžete provést následující kontroly:
- Stavový kód vrácený SUT může být zkontrolován podle očekávaného
HttpStatusCode.Redirectvýsledku, nikoli z konečného stavového kódu po přesměrování na přihlašovací stránku, která by byla HttpStatusCode. ok. LocationHodnota hlavičky v hlavičkách odpovědi je zaškrtnuta, aby se ověřilo, že začínáhttp://localhost/Identity/Account/Login, a ne konečná odpověď přihlašovací stránky, kde by tato hlavička nebyla kLocationdispozici.
Testovací aplikace může AuthenticationHandler<TOptions> ConfigureTestServices napodobovat, aby mohla testovat aspekty ověřování a autorizace. Minimální scénář vrátí AuthenticateResult.Success :
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);
}
}
TestAuthHandlerJe volána k ověření uživatele, pokud je schéma ověřování nastaveno na umístění, Test kde AddAuthentication je zaregistrováno pro ConfigureTestServices . Je důležité, Test aby schéma odpovídalo schématu, které vaše aplikace očekává. V opačném případě ověřování nebude fungovat.
[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);
}
Další informace o naleznete v WebApplicationFactoryClientOptions části Možnosti klienta .
Nastavení prostředí
Ve výchozím nastavení je hostitel a prostředí aplikace SUT nakonfigurovaná tak, aby používala vývojové prostředí. Přepsání prostředí SUT při použití IHostBuilder :
- Nastavte
ASPNETCORE_ENVIRONMENTproměnnou prostředí (například,StagingProductionnebo jinou vlastní hodnotu, napříkladTesting). - Přepsání
CreateHostBuilderv testovací aplikaci pro čtení proměnných prostředí s předponouASPNETCORE.
protected override IHostBuilder CreateHostBuilder() =>
base.CreateHostBuilder()
.ConfigureHostConfiguration(
config => config.AddEnvironmentVariables("ASPNETCORE"));
Pokud SUT používá webového hostitele ( IWebHostBuilder ), přepište CreateWebHostBuilder :
protected override IWebHostBuilder CreateWebHostBuilder() =>
base.CreateWebHostBuilder().UseEnvironment("Testing");
Jak testovací infrastruktura odvodí kořenovou cestu obsahu aplikace
WebApplicationFactoryKonstruktor odvodí kořenovou cestu obsahu aplikace hledáním na sestavení, které WebApplicationFactoryContentRootAttribute obsahuje testy integrace s klíčem, který se rovná TEntryPoint sestavení System.Reflection.Assembly.FullName . V případě, že atribut se správným klíčem nebyl nalezen, WebApplicationFactory vrátí se zpět k hledání souboru řešení (. sln) a připojí TEntryPoint název sestavení k adresáři řešení. Kořenový adresář aplikace (kořenová cesta obsahu) se používá ke zjišťování zobrazení a souborů obsahu.
Zakázat stínové kopírování
Stínové kopírování způsobí, že se testy spustí v jiném adresáři než výstupní adresář. Pokud vaše testy spoléhají na načítání souborů vzhledem k Assembly.Location problémům a narazíte na problémy, může být nutné zakázat stínové kopírování.
Chcete-li zakázat stínové kopírování při použití xUnit, vytvořte xunit.runner.json soubor v adresáři testovacího projektu se správným nastavením konfigurace:
{
"shadowCopy": false
}
Vyřazení objektů
Po provedení testů pro IClassFixture implementaci TestServer a HttpClient jsou uvolněny, když xUnit odstraní WebApplicationFactory . Pokud objekty, které vytvořil vývojář, vyžadují likvidaci, jejich uvolnění v IClassFixture implementaci. Další informace naleznete v tématu implementace metody Dispose.
Ukázka integračních testů
Ukázková aplikace se skládá ze dvou aplikací:
| Aplikace | Adresář projektu | Popis |
|---|---|---|
| Aplikace zprávy (SUT) | src/RazorPagesProject |
Povoluje uživateli přidávat, odstraňovat a analyzovat zprávy a analyzovat je. |
| Testovací aplikace | tests/RazorPagesProject.Tests |
Používá se k testování integrace SUT. |
Testy lze spustit pomocí integrovaných testovacích funkcí integrovaného vývojového prostředí, jako je Visual Studio. Pokud používáte Visual Studio Code nebo příkazový řádek, spusťte na příkazovém řádku v adresáři následující tests/RazorPagesProject.Tests příkaz:
dotnet test
Organizace aplikace zpráv (SUT)
SUT je systém Razor zpráv Pages s následujícími charakteristikami:
- Stránka Index aplikace ( a ) poskytuje metody uživatelského rozhraní a modelu stránky pro řízení přidávání, odstraňování a analýzy zpráv
Pages/Index.cshtmlPages/Index.cshtml.cs(průměrná slova na zprávu). - Zpráva je popsána
Messagetřídou (Data/Message.cs) se dvěma vlastnostmi:Id(klíč) aText(zpráva). VlastnostTextje povinná a omezená na 200 znaků. - Zprávy se ukládají pomocí Entity Framework databáze v paměti†.
- Aplikace obsahuje vrstvu přístupu k datům (DAL) ve třídě kontextu databáze
AppDbContext(Data/AppDbContext.cs). - Pokud je databáze při spuštění aplikace prázdná, inicializuje se úložiště zpráv se třemi zprávami.
- Aplikace obsahuje objekt
/SecurePage, ke kterým má přístup pouze ověřený uživatel.
†tématu EF, Test with InMemory, vysvětluje, jak používat databázi v paměti pro testy pomocí MSTestu. Toto téma používá testovací rozhraní xUnit. Koncepty testů a implementace testů v různých testovacích architekturách jsou podobné, ale nejsou identické.
I když aplikace vzor úložiště nevyu používá a není efektivním příkladem vzoru UoW (Unit of Work),Pages podporuje tyto vzory Razor vývoje. Další informace najdete v tématu Návrh vrstvy trvalosti infrastruktury a Logika testovacího kontroleru (ukázka implementuje vzor úložiště).
Otestování organizace aplikace
Testovací aplikace je konzolová aplikace v tests/RazorPagesProject.Tests adresáři .
| Testování adresáře aplikace | Description |
|---|---|
AuthTests |
Obsahuje testovací metody pro:
|
BasicTests |
Obsahuje testovací metodu pro směrování a typ obsahu. |
IntegrationTests |
Obsahuje integrační testy pro indexovou stránku pomocí vlastní WebApplicationFactory třídy . |
Helpers/Utilities |
|
Testovací rozhraní je xUnit. Integrační testy se provádějí pomocí Microsoft.AspNetCore.TestHost , který zahrnuje TestServer . Vzhledem k tomu, že se balíček používá ke konfiguraci testovacího hostitele a testovacího serveru, nevyžadují balíčky a přímé odkazy na balíčky v souboru projektu testovací aplikace ani v konfiguraci vývojáře v Microsoft.AspNetCore.Mvc.Testing TestHost testovací TestServer aplikaci.
Integrační testy obvykle před provedením testu vyžadují malou datovou sadu v databázi. Například testovací odstranění volá odstranění záznamu databáze, takže databáze musí mít alespoň jeden záznam, aby byla žádost o odstranění úspěšná.
Ukázková aplikace do databáze přisudí tři Utilities.cs zprávy, které mohou testy použít při jejich spuštění:
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." }
};
}
Kontext databáze SUT je zaregistrovaný ve své Startup.ConfigureServices metodě. Zpětné volání testovací aplikace se spustí po spuštění kódu builder.ConfigureServices Startup.ConfigureServices aplikace. Pokud chcete pro testy použít jinou databázi, je nutné nahradit kontext databáze aplikace v builder.ConfigureServices . Další informace najdete v části Přizpůsobení WebApplicationFactory.
U SUT, které stále používají webového hostitele,se zpětné volání testovací aplikace provádí před builder.ConfigureServices kódem SUT. Startup.ConfigureServices Zpětné volání testovací builder.ConfigureTestServices aplikace se spustí po.