← ASP.NET Core: aplicações, contratos e operação
08 / 10 · 60 MIN

Âmbito de testes e evidência de integração

Delimita o que um teste de integração demonstra através do host, dos serviços substituídos, do estado e das observações recolhidas.

O host define o âmbito

WebApplicationFactory prepara um host de teste e um cliente que pode atravessar routing, middleware e serviços configurados. Isso é diferente de chamar diretamente uma função do endpoint. Contudo, TestServer não demonstra o trajeto pelo balanceador, o certificado servido ou o comportamento da infraestrutura de produção.

Antes de interpretar um resultado, identifica quais componentes estão no host, quais foram substituídos e quais nunca receberam o pedido.

Primeira resposta e resposta final

Um cliente que segue redirecionamentos pode receber o HTML do login com 200 depois de um 302 inicial. Se o objetivo é observar o challenge de uma página Razor com cookies e redirecionamento configurado, usa AllowAutoRedirect=false e avalia estado e Location.

Esse cenário não deve ser generalizado para uma API JWT bearer, cujo challenge é 401. Um BaseAddress com HTTPS também não transforma TestServer numa prova do TLS publicado.

Substituir uma dependência

ConfigureTestServices permite fornecer uma implementação controlada para o cenário. No excerto, RemoveAll retira os registos de IStockLookup e o stub devolve null; a asserção observa a transformação desse resultado em 404. A integração com a base real está fora desse pedido.

Confirma que o endpoint usa efetivamente essa interface e que não há outra implementação capturada anteriormente. Documenta a substituição junto da conclusão, para não atribuir ao teste a consulta que ele omitiu.

Identidade de teste

Um handler de teste pode criar um principal com claims sintéticas através de AuthenticateResult.Success. O esquema tem de corresponder ao que o host seleciona. Essa técnica permite estudar a decisão da política para identidades conhecidas, incluindo permissão presente ou ausente.

A assinatura, o emissor, a audience e a validade temporal de um JWT real não são validados por essa identidade fabricada. Mantém separadas as alegações sobre autorização e sobre aceitação de credenciais.

Estado inicial e efeitos

Cada cenário deve estabelecer os dados de que depende. Se um teste elimina linhas usadas por outro, uma falha dependente da ordem pode resultar da preparação, sem demonstrar um defeito do endpoint. Isola stores ou repõe dados de forma controlada.

Quando o contrato diz rejeitar sem criar, observa a resposta de validação e o estado posterior. Apenas 400 não prova ausência de escrita; apenas ausência de exceção no método de teste também não confirma o contrato funcional.

Provider e consulta real

SQLite pode ser útil como substituto relacional, mas comparação de texto, tradução LINQ e SQL específico podem diferir do SQL Server escolhido para produção. EF InMemory não é uma base relacional e não demonstra rollback transacional SQL. Um repositório que devolve DTOs prontos retira também a consulta da fronteira exercitada.

Escolhe a verificação necessária à alegação: resposta do consumidor, comportamento da consulta ou semântica do provider. Nenhum substituto prova automaticamente os três.

Conclusão limitada à configuração

UseEnvironment("Development") torna explícito um ambiente de teste, mas não verifica automaticamente os ramos de configuração e de erros usados em Production. O mesmo vale para autenticação substituída, estado sintético e serviços externos omitidos.

Num registo de aceitação, descreve pedido, resultado esperado, estado observado e fronteiras excluídas. Se uma lista fixa de dois DTOs produziu 200, a conclusão cobre o consumidor; para afirmar filtragem SQL correta é necessária evidência da implementação e do provider relevantes.

// Reading example for an ASP.NET Core 10 xUnit test project.
// Prerequisites: Microsoft.AspNetCore.Mvc.Testing 10.x, xUnit,
// a reference to the SUT, and its public Program and IStockLookup types.
// SUT contract: anonymous GET /stock/{id:int} calls Find(id);
// null produces 404, otherwise 200 with JSON { id, units }.
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Xunit;

public sealed class StockResponseTests
{
    [Fact]
    public async Task Missing_stock_returns_not_found()
    {
        using var baseFactory = new WebApplicationFactory<Program>();
        using var factory = baseFactory.WithWebHostBuilder(builder =>
            builder.ConfigureTestServices(services =>
            {
                services.RemoveAll<IStockLookup>();
                services.AddSingleton<IStockLookup>(new MissingStock());
            }));
        using var client = factory.CreateClient(
            new WebApplicationFactoryClientOptions { AllowAutoRedirect = false });
        using var response = await client.GetAsync("/stock/42");
        Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
    }

    // SUT interface premise: StockRow? Find(int id).
    // StockRow and IStockLookup are supplied by the referenced SUT.
    private sealed class MissingStock : IStockLookup
    {
        public StockRow? Find(int id) => null;
    }
}
NA PRÁTICA

O exemplo é um excerto de leitura com contratos do SUT declarados, não um projeto autónomo. O pedido atravessa o host com IStockLookup substituído; a asserção verifica 404 para o resultado null. Não verifica a consulta real, autenticação, escrita ou TLS de produção.

Se a implementação do SUT tiver outro contrato ou usar uma dependência diferente, o excerto precisa de ser adaptado. A avaliação pede interpretar estas fronteiras, sem executar o teste.

Armadilhas comuns

Seguir um redirecionamento até ao login pode transformar um challenge inicial num 200 final. Claims sintéticas não validam JWT. SQLite e InMemory não reproduzem todas as regras do provider de produção. Um estado partilhado sem reposição torna resultados dependentes da ordem.

Tópicos relacionados: Autenticação e autorização · Persistência e concorrência · Saúde, observabilidade e diagnóstico

Leva esta ideia contigo

Nomeia o comportamento observado e as dependências realmente atravessadas. Mantém as premissas de cada cenário explícitas e escolhe evidência adicional para as fronteiras excluídas.

Criar conta

Referência: Integration host and request path · ASP.NET Core 10.0 / .NET 10 / C# 14