Testowanie aplikacji MVC ASP.NET Core
Napiwek
Ta zawartość jest fragmentem książki eBook, architekta nowoczesnych aplikacji internetowych z platformą ASP.NET Core i platformą Azure, dostępnym na platformie .NET Docs lub jako bezpłatny plik PDF do pobrania, który można odczytać w trybie offline.
"Jeśli nie lubisz testowania jednostkowego produktu, najprawdopodobniej klienci nie będą chcieli go przetestować. _-Anonimowy-
Oprogramowanie dowolnej złożoności może zakończyć się niepowodzeniem w nieoczekiwany sposób w odpowiedzi na zmiany. W związku z tym testowanie po wprowadzeniu zmian jest wymagane dla wszystkich, ale najbardziej trywialnych (lub najmniej krytycznych) aplikacji. Testowanie ręczne to najwolniejszy, najmniej niezawodny, najdroższy sposób testowania oprogramowania. Niestety, jeśli aplikacje nie są przeznaczone do testowania, może to być jedyny dostępny środek testowania. Aplikacje napisane zgodnie z zasadami architektury określonymi w rozdziale 4 powinny być w dużej mierze testowalne jednostkowe. aplikacje ASP.NET Core obsługują zautomatyzowaną integrację i testowanie funkcjonalne.
Rodzaje testów automatycznych
Istnieje wiele rodzajów testów automatycznych dla aplikacji oprogramowania. Najprostszym, najniższym testem poziomu jest test jednostkowy. Na nieco wyższym poziomie istnieją testy integracji i testy funkcjonalne. Inne rodzaje testów, takich jak testy interfejsu użytkownika, testy obciążeniowe, testy obciążeniowe i testy weryfikacyjne kompilacji, wykraczają poza zakres tego dokumentu.
Testy jednostkowe
Test jednostkowy testuje pojedynczą część logiki aplikacji. Można to jeszcze bardziej opisać, wymieniając niektóre rzeczy, których nie ma. Test jednostkowy nie testuje sposobu działania kodu z zależnościami lub infrastrukturą — to właśnie są testy integracji. Test jednostkowy nie testuje struktury, na której jest napisany kod — należy założyć, że działa lub, jeśli go nie znajdziesz, zgłoś usterkę i kod obejścia. Test jednostkowy jest uruchamiany całkowicie w pamięci i w trakcie procesu. Nie komunikuje się z systemem plików, siecią ani bazą danych. Testy jednostkowe powinny testować tylko kod.
Testy jednostkowe, ze względu na fakt, że testują tylko jedną jednostkę kodu bez zależności zewnętrznych, powinny być wykonywane bardzo szybko. W związku z tym powinno być możliwe uruchamianie zestawów testów setek testów jednostkowych w ciągu kilku sekund. Uruchamiaj je często, najlepiej przed każdym wypchnięciem do udostępnionego repozytorium kontroli źródła, a na pewno przy każdej automatycznej kompilacji na serwerze kompilacji.
Testy integracji
Chociaż dobrze jest hermetyzować kod, który wchodzi w interakcję z infrastrukturą, np. bazami danych i systemami plików, nadal będziesz mieć część tego kodu i prawdopodobnie zechcesz go przetestować. Ponadto należy sprawdzić, czy warstwy kodu współdziałają zgodnie z oczekiwaniami, gdy zależności aplikacji zostaną w pełni rozwiązane. Ta funkcja jest odpowiedzialna za testy integracji. Testy integracji są zwykle wolniejsze i trudniejsze do skonfigurowania niż testy jednostkowe, ponieważ często zależą one od zależności zewnętrznych i infrastruktury. Dlatego należy unikać testowania elementów, które mogą być testowane przy użyciu testów jednostkowych w testach integracji. Jeśli możesz przetestować dany scenariusz przy użyciu testu jednostkowego, należy przetestować go przy użyciu testu jednostkowego. Jeśli nie możesz, rozważ użycie testu integracji.
Testy integracji często mają bardziej złożone procedury konfiguracji i usuwania, niż testy jednostkowe. Na przykład test integracji, który jest przeciwny rzeczywistej bazie danych, będzie potrzebował sposobu zwrócenia bazy danych do znanego stanu przed każdym uruchomieniem testu. W miarę dodawania nowych testów i rozwoju schematu produkcyjnej bazy danych te skrypty testowe będą miały tendencję do wzrostu rozmiaru i złożoności. W wielu dużych systemach niepraktyczne jest uruchamianie pełnych zestawów testów integracji na stacjach roboczych deweloperów przed zaewidencjonowanie zmian w udostępnionej kontroli źródła. W takich przypadkach testy integracji mogą być uruchamiane na serwerze kompilacji.
Testy funkcjonalne
Testy integracji są napisane z perspektywy dewelopera, aby sprawdzić, czy niektóre składniki systemu działają prawidłowo. Testy funkcjonalne są pisane z perspektywy użytkownika i weryfikują poprawność systemu w oparciu o jego wymagania. Poniższy fragment oferuje przydatną analogię do tego, jak myśleć o testach funkcjonalnych, w porównaniu z testami jednostkowym:
"Wiele razy rozwój systemu jest podobny do budynku domu. Chociaż ta analogia nie jest całkiem poprawna, możemy ją rozszerzyć na potrzeby zrozumienia różnicy między testami jednostkowym i funkcjonalnymi. Testy jednostkowe są analogiczne do inspektora budynku odwiedzającego plac budowy domu. Koncentruje się na różnych systemach wewnętrznych domu, fundamentach, oprawach, elektrycznych, kanalizacyjnych itd. Zapewnia (testy), że części domu będą działać prawidłowo i bezpiecznie, tj. spełniają kod budynku. Testy funkcjonalne w tym scenariuszu są analogiczne do właścicieli domów odwiedzających ten sam plac budowy. Zakłada, że systemy wewnętrzne będą zachowywać się odpowiednio, że inspektor budowlany wykonuje swoje zadanie. Właściciel domu koncentruje się na tym, jak będzie to wyglądać, aby mieszkać w tym domu. Jest zaniepokojony tym, jak wygląda dom, są różne pokoje wygodne wielkości, czy dom pasuje do potrzeb rodziny, są okna w dobrym miejscu, aby złapać rano słońce. Właściciel domu wykonuje testy funkcjonalne w domu. Ma perspektywę użytkownika. Inspektor budowlany przeprowadza testy jednostkowe w domu. Ma perspektywę budowniczego."
Źródło: Testy jednostkowe i testy funkcjonalne
Lubię mówić: "Jako deweloperzy, kończymy się niepowodzeniem na dwa sposoby: tworzymy coś złego lub budujemy złą rzecz". Testy jednostkowe zapewniają, że tworzysz coś w porządku; testy funkcjonalne zapewniają, że tworzysz właściwą rzecz.
Ponieważ testy funkcjonalne działają na poziomie systemu, mogą wymagać pewnego stopnia automatyzacji interfejsu użytkownika. Podobnie jak testy integracji, zwykle współpracują one z jakąś infrastrukturą testów. To działanie sprawia, że są wolniejsze i bardziej kruche niż testy jednostkowe i integracyjne. Należy mieć tylko tyle testów funkcjonalnych, jak trzeba mieć pewność, że system działa zgodnie z oczekiwaniami użytkowników.
Piramida testowania
Martin Fowler napisał o piramidzie testowej, której przykład pokazano na rysunku 9-1.
Rysunek 9–1. Piramida testowania
Różne warstwy ostrosłupu i ich względne rozmiary reprezentują różne rodzaje testów i liczbę, które należy napisać dla aplikacji. Jak widać, zaleceniem jest posiadanie dużej bazy testów jednostkowych obsługiwanych przez mniejszą warstwę testów integracji z jeszcze mniejszą warstwą testów funkcjonalnych. Każda warstwa powinna mieć w nim tylko testy, których nie można wykonać odpowiednio w niższej warstwie. Pamiętaj o piramidzie testowej, gdy próbujesz zdecydować, jakiego rodzaju test jest potrzebny w konkretnym scenariuszu.
Co należy przetestować
Typowy problem dla deweloperów, którzy nie mają doświadczenia z pisaniem testów automatycznych, jest wymyślany, co należy przetestować. Dobrym punktem wyjścia jest przetestowanie logiki warunkowej. W dowolnym miejscu masz metodę z zachowaniem, które zmienia się na podstawie instrukcji warunkowej (if-else, switch itd.), powinno być możliwe wymyślenie co najmniej kilku testów, które potwierdzają prawidłowe zachowanie w określonych warunkach. Jeśli kod ma warunki błędu, warto napisać co najmniej jeden test dla "szczęśliwej ścieżki" za pośrednictwem kodu (bez błędów) i co najmniej jeden test dla "smutnej ścieżki" (z błędami lub nietypowymi wynikami), aby potwierdzić, że aplikacja zachowuje się zgodnie z oczekiwaniami w obliczu błędów. Na koniec spróbuj skupić się na testowaniu rzeczy, które mogą zakończyć się niepowodzeniem, zamiast skupiać się na metrykach, takich jak pokrycie kodu. Więcej pokrycia kodu jest lepsze niż mniej, ogólnie. Jednak pisanie kilku kolejnych testów złożonej i krytycznej dla działania firmy metody jest zwykle lepszym użyciem czasu niż pisanie testów dla właściwości automatycznych tylko w celu poprawy metryk pokrycia kodu testowego.
Organizowanie projektów testowych
Projekty testowe można organizować, jednak najlepiej dla Ciebie. Dobrym pomysłem jest oddzielenie testów według typu (testu jednostkowego, testu integracji) i testów testowych (według projektu, według przestrzeni nazw). To, czy separacja składa się z folderów w ramach jednego projektu testowego, czy wielu projektów testowych, jest decyzją projektową. Jeden projekt jest najprostszy, ale w przypadku dużych projektów z wieloma testami lub w celu łatwiejszego uruchamiania różnych zestawów testów warto mieć kilka różnych projektów testowych. Wiele zespołów organizuje projekty testowe w oparciu o projekt, który w przypadku aplikacji z więcej niż kilkoma projektami może spowodować dużą liczbę projektów testowych, zwłaszcza jeśli nadal podzielisz je zgodnie z rodzajem testów w każdym projekcie. Podejście do naruszenia zabezpieczeń polega na tym, że jeden projekt na rodzaj testu, na aplikację, z folderami wewnątrz projektów testowych, aby wskazać testowany projekt (i klasę).
Typowym podejściem jest organizowanie projektów aplikacji w folderze "src" i projektach testowych aplikacji w ramach równoległego folderu "testy". Jeśli okaże się, że ta organizacja jest przydatna, możesz utworzyć pasujące foldery rozwiązań w programie Visual Studio.
Rysunek 9–2. Testowanie organizacji w rozwiązaniu
Możesz użyć dowolnej preferowanej platformy testowej. Struktura xUnit działa dobrze i jest to, w czym są napisane wszystkie testy ASP.NET Core i EF Core. Projekt testowy xUnit można dodać w programie Visual Studio przy użyciu szablonu pokazanego na rysunku 9-3 lub z poziomu interfejsu wiersza polecenia przy użyciu polecenia dotnet new xunit
.
Rysunek 9–3. Dodawanie projektu testowego xUnit w programie Visual Studio
Nazewnictwo testów
Nazwij testy w spójny sposób z nazwami wskazującymi, co robi każdy test. Jednym z metod, z którymi odniósłem wielki sukces, jest nazwanie klas testowych zgodnie z klasą i metodą, którą testują. Takie podejście powoduje wiele małych klas testowych, ale sprawia, że bardzo jasne jest, co każdy test jest odpowiedzialny. Po skonfigurowaniu nazwy klasy testowej w celu zidentyfikowania klasy i metody do przetestowania można użyć nazwy metody testowej w celu określenia testowanego zachowania. Ta nazwa powinna zawierać oczekiwane zachowanie oraz wszelkie dane wejściowe lub założenia, które powinny przynieść to zachowanie. Przykładowe nazwy testów:
CatalogControllerGetImage.CallsImageServiceWithId
CatalogControllerGetImage.LogsWarningGivenImageMissingException
CatalogControllerGetImage.ReturnsFileResultWithBytesGivenSuccess
CatalogControllerGetImage.ReturnsNotFoundResultGivenImageMissingException
Odmiana tego podejścia kończy każdą nazwę klasy testowej z wartością "Powinna" i nieznacznie modyfikuje czas:
CatalogControllerGetImage
Powinno wywołać.
ImageServiceWithId
CatalogControllerGetImage
Powinien rejestrować.
WarningGivenImageMissingException
Niektóre zespoły uważają drugie podejście nazewnictwa jaśniejsze, choć nieco bardziej pełne. W każdym razie spróbuj użyć konwencji nazewnictwa, która zapewnia wgląd w zachowanie testowe, dzięki czemu w przypadku niepowodzenia co najmniej jednego testu jest oczywiste z ich nazw, jakie przypadki zakończyły się niepowodzeniem. Unikaj nazewnictwa testów niejasno, takich jak ControllerTests.Test1, ponieważ te nazwy nie oferują żadnej wartości, gdy są one widoczne w wynikach testu.
Jeśli stosujesz konwencję nazewnictwa, taką jak powyżej, która generuje wiele małych klas testowych, dobrym pomysłem jest dalsze organizowanie testów przy użyciu folderów i przestrzeni nazw. Rysunek 9–4 przedstawia jedno podejście do organizowania testów według folderu w kilku projektach testowych.
Rysunek 9–4. Organizowanie klas testowych według folderu na podstawie testowanej klasy.
Jeśli określona klasa aplikacji ma wiele testowanych metod (a tym samym wiele klas testowych), warto umieścić te klasy w folderze odpowiadającym klasie aplikacji. Ta organizacja nie różni się od sposobu organizowania plików w folderach gdzie indziej. Jeśli masz więcej niż trzy lub cztery powiązane pliki w folderze zawierającym wiele innych plików, często warto przenieść je do własnego podfolderu.
Testowanie jednostkowe aplikacji ASP.NET Core
W dobrze zaprojektowanej aplikacji ASP.NET Core większość złożoności i logiki biznesowej będzie hermetyzowana w jednostkach biznesowych i różnych usługach. Sama aplikacja MVC platformy ASP.NET Core z kontrolerami, filtrami, modelami widoków i widokami powinna wymagać kilku testów jednostkowych. Wiele funkcji danej akcji leży poza samą metodą akcji. Testowanie, czy routing czy globalna obsługa błędów działa prawidłowo, nie można wykonać skutecznie przy użyciu testu jednostkowego. Podobnie wszystkie filtry, w tym filtry weryfikacji modelu i uwierzytelniania i autoryzacji, nie mogą być testowane jednostkowo z testem ukierunkowanym na metodę akcji kontrolera. Bez tych źródeł zachowania większość metod akcji powinna być trywialnie mała, delegując większość ich pracy do usług, które mogą być testowane niezależnie od kontrolera, który z nich korzysta.
Czasami należy refaktoryzować kod w celu przetestowania go jednostkowego. Często to działanie obejmuje identyfikowanie abstrakcji i używanie iniekcji zależności w celu uzyskania dostępu do abstrakcji w kodzie, który chcesz przetestować, zamiast kodować bezpośrednio względem infrastruktury. Rozważmy na przykład tę łatwą metodę akcji do wyświetlania obrazów:
[HttpGet("[controller]/pic/{id}")]
public IActionResult GetImage(int id)
{
var contentRoot = _env.ContentRootPath + "//Pics";
var path = Path.Combine(contentRoot, id + ".png");
Byte[] b = System.IO.File.ReadAllBytes(path);
return File(b, "image/png");
}
Testowanie jednostkowe tej metody jest utrudnione przez bezpośrednią zależność od System.IO.File
metody , która jest używana do odczytu z systemu plików. To zachowanie można przetestować, aby upewnić się, że działa zgodnie z oczekiwaniami, ale w przypadku rzeczywistych plików jest testem integracji. Warto zauważyć, że nie można testować jednostkowo trasy tej metody — wkrótce zobaczysz, jak wykonać to testowanie przy użyciu testu funkcjonalnego.
Jeśli nie możesz bezpośrednio przetestować zachowania systemu plików i nie możesz przetestować trasy, co należy przetestować? Po refaktoryzacji, aby umożliwić testowanie jednostkowe, możesz odnaleźć niektóre przypadki testowe i brakujące zachowanie, takie jak obsługa błędów. Co robi metoda, gdy plik nie zostanie znaleziony? Co należy zrobić? W tym przykładzie refaktoryzowana metoda wygląda następująco:
[HttpGet("[controller]/pic/{id}")]
public IActionResult GetImage(int id)
{
byte[] imageBytes;
try
{
imageBytes = _imageService.GetImageBytesById(id);
}
catch (CatalogImageMissingException ex)
{
_logger.LogWarning($"No image found for id: {id}");
return NotFound();
}
return File(imageBytes, "image/png");
}
_logger
i _imageService
są wstrzykiwane jako zależności. Teraz możesz przetestować, czy ten sam identyfikator, który jest przekazywany do metody akcji, jest przekazywany do _imageService
metody , i że wynikowe bajty są zwracane w ramach elementu FileResult. Możesz również przetestować, czy rejestrowanie błędów odbywa się zgodnie z oczekiwaniami, i że NotFound
wynik jest zwracany, jeśli brakuje obrazu, zakładając, że to zachowanie jest ważnym zachowaniem aplikacji (czyli nie tylko tymczasowym kodem dodanym przez dewelopera w celu zdiagnozowania problemu). Rzeczywista logika plików została przeniesiona do oddzielnej usługi implementacji i została rozszerzona w celu zwrócenia wyjątku specyficznego dla aplikacji w przypadku brakującego pliku. Tę implementację można przetestować niezależnie przy użyciu testu integracji.
W większości przypadków należy użyć globalnych procedur obsługi wyjątków w kontrolerach, więc ilość logiki w nich powinna być minimalna i prawdopodobnie nie warto testować jednostkowe. Wykonaj większość testów akcji kontrolera przy użyciu testów funkcjonalnych i TestServer
klasy opisanej poniżej.
Testowanie integracji ASP.NET Core aplikacji
Większość testów integracji w aplikacjach ASP.NET Core powinna testować usługi i inne typy implementacji zdefiniowane w projekcie Infrastruktura. Można na przykład przetestować , że program EF Core pomyślnie aktualizuje i pobiera dane oczekiwane z klas dostępu do danych znajdujących się w projekcie Infrastruktura. Najlepszym sposobem na przetestowanie, czy projekt ASP.NET Core MVC działa prawidłowo, to testy funkcjonalne uruchamiane względem aplikacji uruchomionej na hoście testowym.
Testowanie funkcjonalne ASP.NET Core
W przypadku aplikacji ASP.NET Core klasa sprawia, TestServer
że testy funkcjonalne są dość łatwe do zapisu. Należy skonfigurować TestServer
przy użyciu WebHostBuilder
typu (lub HostBuilder
) bezpośrednio (tak jak zwykle w przypadku aplikacji) lub z WebApplicationFactory
typem (dostępnym od wersji 2.1). Spróbuj dopasować hosta testowego do hosta produkcyjnego tak ściśle, jak to możliwe, aby testy działały podobnie jak w przypadku aplikacji w środowisku produkcyjnym. Klasa WebApplicationFactory
jest przydatna do konfigurowania elementu ContentRoot serwera TestServer, który jest używany przez ASP.NET Core do lokalizowania zasobu statycznego, takiego jak Widoki.
Proste testy funkcjonalne można utworzyć, tworząc klasę testową, która implementuje IClassFixture<WebApplicationFactory<TEntryPoint>>
klasę , gdzie TEntryPoint
jest klasą Startup
aplikacji internetowej. Dzięki temu interfejsowi urządzenie testowe może utworzyć klienta przy użyciu metody fabryki CreateClient
:
public class BasicWebTests : IClassFixture<WebApplicationFactory<Program>>
{
protected readonly HttpClient _client;
public BasicWebTests(WebApplicationFactory<Program> factory)
{
_client = factory.CreateClient();
}
// write tests that use _client
}
Napiwek
Jeśli używasz minimalnej konfiguracji interfejsu API w pliku Program.cs, domyślnie klasa zostanie zadeklarowana jako wewnętrzna i nie będzie dostępna z projektu testowego. Zamiast tego możesz wybrać dowolną inną klasę wystąpień w projekcie internetowym lub dodać tę klasę do pliku Program.cs :
// Make the implicit Program class public so test projects can access it
public partial class Program { }
Często należy wykonać dodatkową konfigurację lokacji przed każdym przebiegiem testu, na przykład skonfigurować aplikację do używania magazynu danych w pamięci, a następnie rozmieszczać aplikację z danymi testowymi. Aby osiągnąć tę funkcję, utwórz własną podklasę WebApplicationFactory<TEntryPoint>
i zastąpij jej ConfigureWebHost
metodę. Poniższy przykład pochodzi z projektu eShopOnWeb FunctionalTests i jest używany jako część testów w głównej aplikacji internetowej.
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb.Infrastructure.Data;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.Web;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
namespace Microsoft.eShopWeb.FunctionalTests.Web;
public class WebTestFixture : WebApplicationFactory<Startup>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseEnvironment("Testing");
builder.ConfigureServices(services =>
{
services.AddEntityFrameworkInMemoryDatabase();
// Create a new service provider.
var provider = services
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
// Add a database context (ApplicationDbContext) using an in-memory
// database for testing.
services.AddDbContext<CatalogContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDbForTesting");
options.UseInternalServiceProvider(provider);
});
services.AddDbContext<AppIdentityDbContext>(options =>
{
options.UseInMemoryDatabase("Identity");
options.UseInternalServiceProvider(provider);
});
// Build the service provider.
var sp = services.BuildServiceProvider();
// Create a scope to obtain a reference to the database
// context (ApplicationDbContext).
using (var scope = sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<CatalogContext>();
var loggerFactory = scopedServices.GetRequiredService<ILoggerFactory>();
var logger = scopedServices
.GetRequiredService<ILogger<WebTestFixture>>();
// Ensure the database is created.
db.Database.EnsureCreated();
try
{
// Seed the database with test data.
CatalogContextSeed.SeedAsync(db, loggerFactory).Wait();
// seed sample user data
var userManager = scopedServices.GetRequiredService<UserManager<ApplicationUser>>();
var roleManager = scopedServices.GetRequiredService<RoleManager<IdentityRole>>();
AppIdentityDbContextSeed.SeedAsync(userManager, roleManager).Wait();
}
catch (Exception ex)
{
logger.LogError(ex, $"An error occurred seeding the " +
"database with test messages. Error: {ex.Message}");
}
}
});
}
}
Testy mogą korzystać z tej niestandardowej klasy WebApplicationFactory, tworząc klienta, a następnie wysyłając żądania do aplikacji przy użyciu tego wystąpienia klienta. Aplikacja będzie mieć dane rozstawione, które mogą być używane w ramach asercji testu. Poniższy test sprawdza, czy strona główna aplikacji eShopOnWeb ładuje się poprawnie i zawiera listę produktów, która została dodana do aplikacji w ramach danych inicjujących.
using Microsoft.eShopWeb.FunctionalTests.Web;
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.eShopWeb.FunctionalTests.WebRazorPages;
[Collection("Sequential")]
public class HomePageOnGet : IClassFixture<WebTestFixture>
{
public HomePageOnGet(WebTestFixture factory)
{
Client = factory.CreateClient();
}
public HttpClient Client { get; }
[Fact]
public async Task ReturnsHomePageWithProductListing()
{
// Arrange & Act
var response = await Client.GetAsync("/");
response.EnsureSuccessStatusCode();
var stringResponse = await response.Content.ReadAsStringAsync();
// Assert
Assert.Contains(".NET Bot Black Sweatshirt", stringResponse);
}
}
Ten test funkcjonalny wykonuje pełne ASP.NET stos aplikacji Core MVC/Razor Pages, w tym wszystkie oprogramowanie pośredniczące, filtry i powiązania, które mogą być w miejscu. Sprawdza, czy dana trasa ("/") zwraca oczekiwany kod stanu powodzenia i dane wyjściowe HTML. Robi to bez konfigurowania rzeczywistego serwera internetowego i pozwala uniknąć znacznej części kruchości, która korzysta z rzeczywistego serwera internetowego do testowania (na przykład problemów z ustawieniami zapory). Testy funkcjonalne uruchamiane względem serwera TestServer są zwykle wolniejsze niż testy integracyjne i jednostkowe, ale są znacznie szybsze niż testy uruchamiane przez sieć do testowego serwera internetowego. Użyj testów funkcjonalnych, aby upewnić się, że stos frontonu aplikacji działa zgodnie z oczekiwaniami. Te testy są szczególnie przydatne podczas znajdowania duplikacji na kontrolerach lub stronach i adresowanie duplikacji przez dodanie filtrów. W idealnym przypadku ta refaktoryzacja nie zmieni zachowania aplikacji, a zestaw testów funkcjonalnych sprawdzi, czy tak jest.
Odwołania — testowanie aplikacji MVC ASP.NET Core
- Testowanie w programie ASP.NET Core
https://learn.microsoft.com/aspnet/core/testing/- Konwencja nazewnictwa testów jednostkowych
https://ardalis.com/unit-test-naming-convention- Testowanie platformy EF Core
https://learn.microsoft.com/ef/core/miscellaneous/testing/- Testy integracji w programie ASP.NET Core
https://learn.microsoft.com/aspnet/core/test/integration-tests