Testar componentes do Razor no ASP.NET Core Blazor

Observação

Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Importante

Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Por Egil Hansen

O teste de componentes do Razor é um aspecto importante do lançamento de aplicativos Blazor estáveis e passíveis de manutenção.

Para testar um componente do Razor, o componente do em teste (CUT) é:

  • Renderizado com entrada relevante para o teste.
  • Dependendo do tipo de teste executado, possivelmente sujeito à interação ou modificação. Por exemplo, manipuladores de eventos podem ser disparados, como um evento onclick para um botão.
  • Inspecionado quanto aos valores esperados. Um teste é aprovado quando um ou mais valores inspecionados correspondem aos valores esperados para o teste.

Abordagens de teste

Duas abordagens comuns para componentes de teste Razor são teste de ponta a ponta (E2E) e teste de unidade:

  • Teste de unidade: os testes de unidade são gravados com uma biblioteca de testes de unidade que fornece:

    • Renderização de componente.
    • Inspeção da saída e do estado do componente.
    • Acionamento de manipuladores de eventos e métodos de ciclo de vida.
    • Declarações de que o comportamento do componente está correto.

    bUnit é um exemplo de uma biblioteca que habilita o teste de unidade de componente do Razor.

  • Teste E2E: um executor de teste executa um aplicativo Blazor que contém a CUT e automatiza uma instância do navegador. A ferramenta de teste inspeciona e interage com o CUT por meio do navegador. Playwright para .NET é um exemplo de uma estrutura de teste E2E que pode ser usada com aplicativos Blazor.

No teste de unidade, somente o componente do Razor (Razor/C#) está envolvido. Dependências externas, como serviços e interoperabilidade JS, devem ser simuladas. No teste do E2E, o componente do Razor e toda a infraestrutura auxiliar fazem parte do teste, incluindo CSS, JS e as APIs do DOM e do navegador.

O escopo do teste descreve a extensão dos testes. O escopo de teste normalmente tem uma influência na velocidade dos testes. Os testes de unidade são executados em um subconjunto dos subsistemas do aplicativo e geralmente são executados em milissegundos. Os testes E2E, que testam um amplo grupo de subsistemas do aplicativo, podem levar vários segundos para serem concluídos.

O teste de unidade também fornece acesso à instância do CUT, permitindo a inspeção e a verificação do estado interno do componente. Normalmente, isso não é possível no teste do E2E.

Em relação ao ambiente do componente, os testes E2E devem garantir que o estado ambiental esperado tenha sido atingido antes do início da verificação. Caso contrário, o resultado será imprevisível. No teste de unidade, a renderização do CUT e o ciclo de vida do teste são mais integrados, o que melhora a estabilidade do teste.

O teste E2E envolve a inicialização de vários processos, E/S de rede e disco e outras atividades de subsistema que geralmente levam à baixa confiabilidade do teste. Os testes de unidade normalmente são isolados desses tipos de problemas.

A tabela a seguir resume as diferenças entre as duas.

Recurso Teste de unidade Teste E2E
Escopo de teste Somente componente Razor (Razor/C#) Componente do Razor (Razor/C#) com CSS/JS
Tempo de execução do teste Milissegundos Segundos
Acesso à instância do componente Sim Não
Sensível ao ambiente Não Sim
Confiabilidade Mais confiável Menos confiável

Escolha a abordagem de teste mais apropriada

Considere o cenário ao escolher o tipo de teste a ser executado. Algumas considerações são descritas na tabela a seguir.

Cenário Abordagem sugerida Comentários
Componente sem lógica de interoperabilidade JS Teste de unidade Quando não há dependência de interoperabilidade JS em um componente Razor, o componente pode ser testado sem acesso a JS ou à API do DOM. Nesse cenário, não há desvantagens na escolha do teste de unidade.
Componente com lógica de interoperabilidade simples JS Teste de unidade É comum que os componentes consultem o DOM ou disparem animações por meio da interoperabilidade JS. O teste de unidade geralmente é preferido nesse cenário, pois é simples simular a interação de JS por meio da interface IJSRuntime.
Componente que depende de código complexo JS Teste de unidade e teste separado JS Se um componente usa JS interoperabilidade para chamar uma biblioteca JS grande ou complexa, mas a interação entre o componente Razor e a biblioteca JS é simples, é provável que a melhor abordagem trate o componente e a biblioteca JS ou o código como duas partes separadas e teste cada uma individualmente. Teste o componente do Razor com uma biblioteca de teste de unidade e teste o JS com uma biblioteca de testes JS.
Componente com lógica que depende da manipulação JS do DOM do navegador Teste E2E Quando a funcionalidade de um componente depender de JS e de sua manipulação do DOM, verifique os códigos JS e Blazor em conjunto em um teste E2E. Essa é a abordagem que os desenvolvedores da estrutura de Blazor tomaram com a lógica de renderização do navegador Blazor, que tem C# e código JS firmemente acoplados. Os códigos C# e JS devem trabalhar juntos para renderizar corretamente os componentes do Razor em um navegador.
Componente que depende da biblioteca de classes de terceiros com dependências difíceis de simular Teste E2E Quando a funcionalidade de um componente depende de uma biblioteca de classes de terceiros que tem dependências difíceis de simular, como interoperabilidade JS, o teste E2E pode ser a única opção para testar o componente.

Testar componentes com bUnit

Não há nenhuma estrutura oficial de teste da Microsoft para Blazor, mas o projeto orientado pela comunidade bUnit fornece uma maneira conveniente de unidade de componentes de teste Razor .

Observação

bUnit é uma biblioteca de testes de terceiros e não tem suporte ou é mantida pela Microsoft.

o bUnit funciona com estruturas de teste de uso geral, como MSTest, NUnit e xUnit. Essas estruturas de teste fazem com que os testes bUnit se pareçam com testes de unidade regulares. Os testes bUnit integrados a uma estrutura de teste de uso geral normalmente são executados com:

Observação

Os conceitos de teste e as implementações de teste em diferentes estruturas de teste são semelhantes, mas não idênticos. Confira a documentação da estrutura de teste para obter diretrizes.

A seguir, demonstra a estrutura de um teste bUnit no componente do Counter em um aplicativo com base em um Blazor modelo de projeto . O componente do Counter exibe e incrementa um contador com base no usuário selecionando um botão na página:

@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

O teste bUnit a seguir verifica se o contador cut é incrementado corretamente quando o botão é selecionado:

@code {
    [Fact]
    public void CounterShouldIncrementWhenClicked()
    {
        // Arrange
        using var ctx = new TestContext();
        var cut = ctx.Render(@<Counter />);
        var paraElm = cut.Find("p");

        // Act
        cut.Find("button").Click();

        // Assert
        var paraElmText = paraElm.TextContent;
        paraElm.MarkupMatches("Current count: 1");
    }
}

Os testes também podem ser escritos em um arquivo de classe C#:

public class CounterTests
{
    [Fact]
    public void CounterShouldIncrementWhenClicked()
    {
        // Arrange
        using var ctx = new TestContext();
        var cut = ctx.RenderComponent<Counter>();
        var paraElm = cut.Find("p");

        // Act
        cut.Find("button").Click();

        // Assert
        var paraElmText = paraElm.TextContent;
        paraElmText.MarkupMatches("Current count: 1");
    }
}

As seguintes ações ocorrem em cada etapa do teste:

  • Organizar: o componente do Counter é renderizado usando o bUnit.TestContext O elemento de parágrafo CUT (<p>) é encontrado e atribuído a paraElm. Em sintaxe Razor, um componente pode ser passado como um RenderFragment para bUnit.

  • Agir: o elemento do botão (<button>) é localizado e, em seguida, selecionado chamando Click, que deve incrementar o contador e atualizar o conteúdo da marca de parágrafo (<p>). O conteúdo do texto do elemento paragraph é obtido chamando TextContent.

  • Assert: MarkupMatches é chamado no conteúdo do texto para verificar se ele corresponde à cadeia de caracteres esperada, que é Current count: 1.

Observação

O método de declaração MarkupMatches difere de uma declaração de comparação de cadeia de caracteres regular (por exemplo, Assert.Equal("Current count: 1", paraElmText);). MarkupMatches executa uma comparação semântica da marcação HTML esperada e de entrada. Uma comparação semântica está ciente da semântica HTML, o que significa que coisas como espaço em branco insignificante são ignoradas. Isso resulta em testes mais estáveis. Para saber mais, confira Personalização da comparação HTML semântica.

Recursos adicionais