Píšete-li unit testy pro ASP.NET Core aplikace, pak jste jen malý krok od automatizovaných integračních testů, které mohou velmi dobře posloužit pro ověření funkčnosti REST API. V ASP.NET Core je to velmi jednoduché díky Host mechanismu.
Integrační testy
Integrační testy pro REST API zákazníci často upřednostňují před Unit Testy. Jak napovídá název, cílem integračních testů je ověřit správnou funkčnost komponent, mezi které patří infrastruktura, databáze, souborový systém nebo další závislosti. Základní předpokladem pro psaní IT je znalost psaní UT, jelikož podpůrná infrastruktura a principy jsou zcela totožné. Mění se zejména úroveň testování. V případě UT obvykle ověřujeme různé scénáře průchodu nad jednotkou kódu (často například metoda C# třídy), zatímco u IT ověřujeme kompletně celý požadavek vůči API.
Provedení integračního testu je náročnější než v případě jednotkového testu. Navíc testovaná jednotka (SUT) odpovídá v podstatě vyřešení HTTP požadavku a tudíž dává smysl testovat v rámci assert fáze rovnou více věcí. To je klíčový rozdíl oproti UT, kde máme jeden assert na jeden test.
Jak fungují integrační testy
Stejně jako u UT založíme testovací projekt. Můžeme volit ze šablon pro NUnit, MSTest nebo xUnit. Já preferuji poslední jmenovaný. Testovací projekt má nareferencovaný celý running projekt - tedy většinou ASP.NET Core aplikaci typu REST API. Pro účely testování se dále používá NuGet balíček Microsoft.AspNetCore.Mvc.Testing a testovací projekt musí mít upraveno SDK na Microsoft.NET.Sdk.Web. To lze změnit v csproj souboru.
Toto nastavení umožňuje pro účely integračních testů vytvořit tzv. WebApplicationFactory a využít ji v testovacím projektu. WebApplicationFactory je generický typ, kterému se předává typ shodný se Startup třídou testované webové aplikace. Principielně tedy WebApplicationFactory drží svůj Host proces (podobně jako bývá v Program.cs/Main) a umožní jednak provedení konfigurace ve Startup.cs a jednak umožňuje tuto konfiguraci přetížit. To se hodí tehdy, když chceme například přepojit běžný SQL Server Provider na lokální Sqlite a nebo nafakeovat některé integrace na vzdálené služby, které testovat nechceme.
Kód níže ilustruje základní nastavení.
public class MyTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly WebApplicationFactory<Startup> _factory;
public MyTests(WebApplicationFactory<RazorPagesProject.Startup> factory)
{
_factory = factory;
}
public async Task MyTest()
{
// Arrange
var client = _factory.CreateClient();
// Act
var response = await client.GetAsync("api/users");
// Assert
response.EnsureSuccessStatusCode();
Assert.Equal("application/json",
response.Content.Headers.ContentType.ToString());
}
}
Dále už je to snadné, protože v samotném testu jednoduše použijeme HttpClient, provoláme vlastní webovou službu a ověříme výsledky požadavku. Vše je tedy postaveno na myšlence, že v rámci spuštění testu se spustí interní host proces, který zpřístupní REST API a následně proti němu pošleme testovací HTTP požadavek pomocí HttpClienta.
Výhody in-memory integračních testů
Je vhodné doplnit, že integrační testy popsané výše jsou založené čistě na principech unit testů a budou je psát obvykle vývojáři nebo testeři se zkušenostmi se C# a .NETem. Označují se často jako in-memory integrační testy. Jsou alternativou vůči tradičním integračním testům (typu Postman / Newman), které běží mimo aplikaci jako SaaS a testují podobným způsobem aplikaci nasazenou v testovacím prostředí.
In-memory integrační testy mají mnoho výhod. V první řadě běží jako součást aplikace a tudíž můžeme sledovat pokrytí testy a v reálném čase ověřovat, zda jsou integrace funkční. Kromě spouštění během vývoje je můžeme zahrnout do CI procesu a tudíž s každým commitem sledovat případné potíže s integrací. Není potřeba aplikaci nikam nasazovat nebo pro ni chystat speciální databázi.
Z hlediska vývoje si může vývojář kód klasicky debuggovat krok za krokem. To vše vede k zrychlení oprav a zachycení chyb dříve, než je aplikace publikována do cílového prostředí. Výhodou je i větší jistota v oblasti security, protože není nutné používat tokeny nebo jiné citlivé údaje mimo běžnou infrastrukturu. Navíc díky možnosti přetížit základní nastavení si lze libovolné části aplikace nafakeovat podle potřeby a testovat tak pouze potřebné komponenty.
Závěr
In-memory integrační testy představují luxusní možnost, jak testovat aplikační komponenty podobně jako v případě unit testů. Vývojář má kompletní komfort vývojářského prostředí a management radost z chyb odchycených ještě před tím, než se dostanou do veřejných prostředí.
Chcete-li se o testování REST API dozvedět více, podívejte se na mou přednášku zaměřenou na testování REST API nebo mrkněte přímo na celodenní školení, které se oblasti testování věnuje.
Kam dále?