Delen via


Test ASP.NET Core-services en web-apps

Tip

Deze inhoud is een fragment uit het eBook, .NET Microservices Architecture for Containerized .NET Applications, beschikbaar op .NET Docs of als een gratis downloadbare PDF die offline kan worden gelezen.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

Controllers vormen een centraal onderdeel van elke ASP.NET Core API-service en ASP.NET MVC-webtoepassing. Als zodanig moet u vertrouwen hebben dat ze zich gedragen zoals bedoeld voor uw toepassing. Geautomatiseerde tests kunnen u deze betrouwbaarheid bieden en kunnen fouten detecteren voordat ze productie bereiken.

U moet testen hoe de controller zich gedraagt op basis van geldige of ongeldige invoer en controllerantwoorden testen op basis van het resultaat van de bedrijfsbewerking die wordt uitgevoerd. U moet echter over dit soort tests beschikken voor uw microservices:

  • Eenheidstests. Deze tests zorgen ervoor dat afzonderlijke onderdelen van de toepassing werken zoals verwacht. Asserties testen de component-API.

  • Integratietests. Deze tests zorgen ervoor dat de interactie van onderdelen werkt zoals verwacht ten opzichte van externe artefacten zoals databases. Asserties kunnen onderdeel-API, gebruikersinterface of de neveneffecten van acties zoals database-I/O, logboekregistratie, enzovoort testen.

  • Functionele tests voor elke microservice. Deze tests zorgen ervoor dat de toepassing werkt zoals verwacht vanuit het perspectief van de gebruiker.

  • Servicetests. Deze tests zorgen ervoor dat end-to-end-servicegebruiksscenario's, waaronder het testen van meerdere services tegelijk, worden getest. Voor dit type test moet u eerst de omgeving voorbereiden. In dit geval betekent dit dat de services worden gestart (bijvoorbeeld door docker-compose up te gebruiken).

Eenheidstests implementeren voor ASP.NET Core Web-API's

Bij het testen van eenheden wordt een deel van een toepassing geïsoleerd van de infrastructuur en afhankelijkheden getest. Wanneer u de logica van de testcontroller eenheid maakt, wordt alleen de inhoud van één actie of methode getest, niet het gedrag van de afhankelijkheden of van het framework zelf. Eenheidstests detecteren geen problemen in de interactie tussen onderdelen, dat is het doel van integratietests.

Terwijl u uw controlleracties test, moet u zich alleen richten op hun gedrag. Een controllereenheidtest voorkomt bijvoorbeeld filters, routering of modelbinding (de toewijzing van aanvraaggegevens aan een ViewModel of DTO). Omdat ze zich richten op het testen van slechts één ding, zijn eenheidstests over het algemeen eenvoudig te schrijven en snel uit te voeren. Een goed geschreven set eenheidstests kan regelmatig worden uitgevoerd zonder veel overhead.

Eenheidstests worden geïmplementeerd op basis van testframeworks zoals xUnit.net, MSTest, Moq of NUnit. Voor de voorbeeldtoepassing eShopOnContainers gebruiken we xUnit.

Wanneer u een eenheidstest schrijft voor een web-API-controller, instantieert u de controllerklasse rechtstreeks met behulp van het nieuwe trefwoord in C#, zodat de test zo snel mogelijk wordt uitgevoerd. In het volgende voorbeeld ziet u hoe u dit doet wanneer u xUnit gebruikt als testframework.

[Fact]
public async Task Get_order_detail_success()
{
    //Arrange
    var fakeOrderId = "12";
    var fakeOrder = GetFakeOrder();

    //...

    //Act
    var orderController = new OrderController(
        _orderServiceMock.Object,
        _basketServiceMock.Object,
        _identityParserMock.Object);

    orderController.ControllerContext.HttpContext = _contextMock.Object;
    var actionResult = await orderController.Detail(fakeOrderId);

    //Assert
    var viewResult = Assert.IsType<ViewResult>(actionResult);
    Assert.IsAssignableFrom<Order>(viewResult.ViewData.Model);
}

Integratie- en functionele tests implementeren voor elke microservice

Zoals vermeld, hebben integratietests en functionele tests verschillende doelen en doelstellingen. De manier waarop u beide implementeert bij het testen van ASP.NET Core-controllers is echter vergelijkbaar, dus in deze sectie concentreren we ons op integratietests.

Integratietests zorgen ervoor dat de onderdelen van een toepassing correct functioneren wanneer ze worden samengesteld. ASP.NET Core biedt ondersteuning voor integratietests met behulp van eenheidstestframeworks en een ingebouwde testwebhost die kan worden gebruikt voor het afhandelen van aanvragen zonder netwerkoverhead.

In tegenstelling tot eenheidstests hebben integratietests vaak betrekking op problemen met de toepassingsinfrastructuur, zoals een database, bestandssysteem, netwerkbronnen of webaanvragen en -antwoorden. Eenheidstests maken gebruik van nep- of mockobjecten in plaats van deze zorgen. Maar het doel van integratietests is om te bevestigen dat het systeem werkt zoals verwacht met deze systemen, dus voor integratietests gebruikt u geen nep- of mockobjecten. In plaats daarvan neemt u de infrastructuur op, zoals databasetoegang of service-aanroep van andere services.

Omdat integratietests grotere codesegmenten dan eenheidstests uitoefenen en omdat integratietests afhankelijk zijn van infrastructuurelementen, zijn ze meestal langzamer dan eenheidstests. Daarom is het een goed idee om te beperken hoeveel integratietests u schrijft en uitvoert.

ASP.NET Core bevat een ingebouwde testwebhost die kan worden gebruikt voor het verwerken van HTTP-aanvragen zonder netwerkoverhead, wat betekent dat u deze tests sneller kunt uitvoeren dan wanneer u een echte webhost gebruikt. De testwebhost (TestServer) is beschikbaar in een NuGet-onderdeel als Microsoft.AspNetCore.TestHost. Het kan worden toegevoegd aan integratietestprojecten en wordt gebruikt voor het hosten van ASP.NET Core-toepassingen.

Zoals u in de volgende code kunt zien, maakt u bij het maken van integratietests voor ASP.NET Core-controllers een instantie van de controllers via de testhost. Deze functionaliteit is vergelijkbaar met een HTTP-aanvraag, maar deze wordt sneller uitgevoerd.

public class PrimeWebDefaultRequestShould
{
    private readonly TestServer _server;
    private readonly HttpClient _client;

    public PrimeWebDefaultRequestShould()
    {
        // Arrange
        _server = new TestServer(new WebHostBuilder()
           .UseStartup<Startup>());
        _client = _server.CreateClient();
    }

    [Fact]
    public async Task ReturnHelloWorld()
    {
        // Act
        var response = await _client.GetAsync("/");
        response.EnsureSuccessStatusCode();
        var responseString = await response.Content.ReadAsStringAsync();
        // Assert
        Assert.Equal("Hello World!", responseString);
    }
}

Aanvullende bronnen

Servicetests implementeren op een toepassing met meerdere containers

Zoals eerder is aangegeven, moeten alle microservices worden uitgevoerd binnen de Docker-host of het containercluster wanneer u toepassingen met meerdere containers test. End-to-end-servicetests met meerdere bewerkingen met verschillende microservices vereisen dat u de hele toepassing in de Docker-host implementeert en start door docker compose up uit te voeren (of een vergelijkbaar mechanisme als u een orchestrator gebruikt). Zodra de hele toepassing en alle bijbehorende services worden uitgevoerd, kunt u end-to-end integratie- en functionele tests uitvoeren.

Er zijn een paar benaderingen die u kunt gebruiken. In het docker-compose.yml-bestand dat u gebruikt om de toepassing te implementeren op oplossingsniveau, kunt u het toegangspunt uitbreiden om dotnet-test te gebruiken. U kunt ook een ander opstelbestand gebruiken waarmee uw tests worden uitgevoerd in de afbeelding die u wilt gebruiken. Door een ander opstelbestand te gebruiken voor integratietests met uw microservices en databases op containers, kunt u ervoor zorgen dat de gerelateerde gegevens altijd opnieuw worden ingesteld op de oorspronkelijke status voordat u de tests uitvoert.

Zodra de opstellen-toepassing actief is, kunt u profiteren van onderbrekingspunten en uitzonderingen als u Visual Studio uitvoert. U kunt ook de integratietests automatisch uitvoeren in uw CI-pijplijn in Azure DevOps Services of een ander CI/CD-systeem dat ondersteuning biedt voor Docker-containers.

Testen in eShopOnContainers

De referentietoepassingstests (eShopOnContainers) zijn onlangs opnieuw gestructureerd en nu zijn er vier categorieën:

  1. Eenheidstests, gewoon oude normale eenheidstests, opgenomen in de {MicroserviceName}. UnitTests-projecten

  2. Functionele/integratietests van microservices, met testcases met betrekking tot de infrastructuur voor elke microservice, maar geïsoleerd van de andere, en zijn opgenomen in de {MicroserviceName}. FunctionalTests-projecten .

  3. Functionele/integratietests van toepassingen, die zich richten op microservicesintegratie, met testcases die verschillende microservices uitoefenen. Deze tests bevinden zich in project Application.FunctionalTests.

Hoewel eenheids- en integratietests zijn ingedeeld in een testmap binnen het microserviceproject, worden toepassings- en belastingstests afzonderlijk beheerd onder de hoofdmap, zoals wordt weergegeven in afbeelding 6-25.

Schermopname van VS die enkele van de testprojecten in de oplossing aanwijst.

Afbeelding 6-25. Mapstructuur testen in eShopOnContainers

Microservice- en toepassingsfunctie-/integratietests worden uitgevoerd vanuit Visual Studio, met behulp van de reguliere testloper, maar eerst moet u de vereiste infrastructuurservices starten, met een set docker-compose-bestanden in de oplossingstestmap:

docker-compose-test.yml

version: '3.4'

services:
  redis.data:
    image: redis:alpine
  rabbitmq:
    image: rabbitmq:3-management-alpine
  sqldata:
    image: mcr.microsoft.com/mssql/server:2017-latest
  nosqldata:
    image: mongo

docker-compose-test.override.yml

version: '3.4'

services:
  redis.data:
    ports:
      - "6379:6379"
  rabbitmq:
    ports:
      - "15672:15672"
      - "5672:5672"
  sqldata:
    environment:
      - SA_PASSWORD=[PLACEHOLDER]
      - ACCEPT_EULA=Y
    ports:
      - "5433:1433"
  nosqldata:
    ports:
      - "27017:27017"

Belangrijk

Microsoft raadt u aan de veiligste verificatiestroom te gebruiken die beschikbaar is. Als u verbinding maakt met Azure SQL, is Managed Identities voor Azure-resources de aanbevolen verificatiemethode.

Als u de functionele/integratietests wilt uitvoeren, moet u deze opdracht eerst uitvoeren vanuit de map voor de oplossingstest:

docker-compose -f docker-compose-test.yml -f docker-compose-test.override.yml up

Zoals u ziet, starten deze docker-compose-bestanden alleen de microservices Redis, RabbitMQ, SQL Server en MongoDB.

Aanvullende bronnen