Afirmar mensagens em testes

Olá de novo. Antecipando o início do curso "Desenvolvedor C #", traduzimos material interessante sobre afirmar mensagens em testes e estamos felizes em compartilhar a tradução com você.




Neste post, falaremos sobre se você deve usar as mensagens Assert em seus testes.

Recebi uma pergunta interessante de um colega leitor, sobre a qual gostaria de me aprofundar em mais detalhes:

Tenho uma pergunta sobre Assert messages: devo usar a sobrecarga que contém o parâmetro message e usá-lo para enviar uma string descrevendo o motivo da falha de Assert (também "Declarações") ?

A resposta a esta pergunta se resume a dois aspectos:

  • Legibilidade do teste - como é fácil entender o que o teste faz.
  • Facilidade de diagnóstico - como é fácil entender por que o teste falha.

Vamos discutir cada um deles individualmente

Legibilidade do teste


As pessoas costumam usar as mensagens Assert para ajudar os membros da equipe e eles mesmos no futuro a entender o que está acontecendo no teste. Vejamos o seguinte exemplo:

[Test]
public void Hiring_a_new_team_member()
{
    var company = new Company();
    var person = new Person(UserType.Customer);

    company.HireNewMember(person);

    Assert.AreEqual(UserType.Employee, person.Type); //  
    Assert.AreEqual(1, company.NumberOfEmployees); //  
}

Em vez de uma declaração simples, você também pode indicar o motivo pelo qual a declaração de teste valida algo:

[Test]
public void Hiring_a_new_team_member()
{
    var company = new Company();
    var person = new Person(UserType.Customer);

    company.HireNewMember(person);

    Assert.AreEqual(UserType.Employee, person.Type, "Person must become an employee after hiring");
    Assert.AreEqual(1, company.NumberOfEmployees, "Number of employees must increase");
}

Tais declarações ajudam, mas têm um preço. Essas mensagens exigem que você

  • Gaste tempo escrevendo-os
  • Mantenha-os seguindo em frente

Aqui, o conjunto de prós e contras é o mesmo dos comentários ao código. E, como no caso dos comentários, aconselho: não escreva mensagens de afirmação apenas para fins de legibilidade. Se você acha que o teste não é óbvio sem afirmar mensagens, tente refatorá-lo. A longo prazo, é mais fácil fazer o teste falar por si mesmo do que mantê-lo sincronizado com as mensagens de afirmação (e isso é apenas uma questão de tempo até que a sincronização seja interrompida).

Insira as mensagens de afirmação somente quando absolutamente necessário - quando você não puder melhorar a legibilidade do teste de nenhuma outra maneira. Mas, mesmo assim, incline-se a optar por não escrevê-las.

A maneira mais fácil de obter um ganho rápido na legibilidade do teste é mudar para um registro de instrução legível. Por exemplo, o NUnit possui um modelo de instrução especial baseado em restrições que ajuda você a escrever suas instruções da seguinte maneira:

[Test]
public void Hiring_a_new_team_member()
{
    var company = new Company();
    var person = new Person(UserType.Customer);

    company.HireNewMember(person);

    Assert.That(person.Type, Is.EqualTo(UserType.Employee));
    Assert.That(company.NumberOfEmployees, Is.EqualTo(1));
}

Ou você pode usar minhas afirmações fluentes favoritas :

[Test]
public void Hiring_a_new_team_member()
{
    var company = new Company();
    var person = new Person(UserType.Customer);

    company.HireNewMember(person);

    person.Type.Should().Be(UserType.Employee);
    company.NumberOfEmployees.Should().Be(1);
}

Essas instruções são lidas em inglês simples - exatamente da maneira que você deseja que todo o seu código seja lido. Nós, humanos, preferimos perceber informações na forma de histórias. Todas as histórias aderem a este modelo:

[] [] [].

Por exemplo,

  .

Aqui - o sujeito, - a ação e - o objeto. O mesmo vale para o código.

Esta versão

company.NumberOfEmployees.Should().Be(1);

lê melhor que

Assert.AreEqual(1, company.NumberOfEmployees);

precisamente porque a história é traçada aqui.
, . , .


Outra visão das mensagens de afirmação é em termos de facilidade de diagnóstico. Em outras palavras, a simplicidade de entender a causa de uma falha no teste sem examinar o código desse teste. Isso é útil ao ler os resultados da montagem do IC.

Do ponto de vista do diagnóstico, siga este guia: se você pode reiniciar facilmente o teste localmente, esse teste não precisará de uma mensagem de confirmação. Isso é válido para todos os testes de unidade (já que eles não funcionam com dependências fora de processo), mas em menor grau para testes de integração e de ponta a ponta.


Pirâmide de teste

Ao subir mais alto na pirâmide de teste, você pode precisar de informações mais detalhadas, porque os testes de integração (e especialmente de ponta a ponta) são mais lentos e você pode não ser capaz de executá-los novamente.

Mas, mesmo com testes de integração e de ponta a ponta, há maneiras de facilitar o diagnóstico sem recorrer à declaração de mensagens:

  • Faça do teste um módulo de comportamento - quando um teste verifica uma coisa, geralmente é fácil determinar o que deu errado. (Isso nem sempre é aplicável aos testes de ponta a ponta, pois você pode querer que esses testes verifiquem como várias unidades de comportamento funcionam de perto).
  • Nomear seus testes de unidade de acordo - O nome ideal do teste descreve o comportamento do aplicativo em termos comerciais, para que até um não programador possa entendê-lo.

E não esqueça que, mesmo sem as instruções do usuário, você ainda possui as mensagens que o ambiente de teste de unidade gera para você.

Por exemplo, um erro na seguinte instrução:

person.Type.Should().Be(UserType.Employee);

dá a seguinte mensagem de erro:

Xunit.Sdk.EqualException: Assert.Equal() Failure
Expected: Employee
Actual:   Customer

A combinação de tais mensagens geradas pelo ambiente e nomes de testes legíveis por humanos torna 90% das mensagens de afirmação do usuário inúteis, mesmo em termos de facilidade de diagnóstico. A única exceção são os longos testes de ponta a ponta. Eles geralmente contêm verificações em vários estágios; portanto, faz sentido usar mensagens de afirmação adicionais para entender qual das etapas falhou. No entanto, não deve haver muitos desses testes de ponta a ponta.

Obviamente, para tirar proveito das mensagens de erro geradas pela estrutura, você precisa evitar comparações booleanas comuns, como:

(person.Type == UserType.Employee).Should().BeTrue();

Porque eles levam à seguinte mensagem de erro:

Xunit.Sdk.TrueException: Assert.True() Failure
Expected: True
Actual:   False

O que não ajuda no diagnóstico.

Sumário


Você costuma se sentir preguiçoso quando se trata de escrever declarações? Bem, agora você pode justificá-lo e enviar seus colegas para este artigo.


“Fico feliz que isso tenha um nome”

Piadas à parte, no entanto, aqui está um resumo:

  • Existem dois aspectos no uso de mensagens de declaração:
    • Legibilidade do teste (como é fácil entender o que o teste faz).
    • Facilidade de diagnóstico (como é fácil entender por que o teste falha durante a criação do IC).
  • Em termos de legibilidade de teste, as mensagens de asserção são comentários de código. Em vez de confiar neles, refatorar seu teste para obter legibilidade.
  • Em termos de facilidade de diagnóstico, a melhor alternativa para afirmar mensagens é:
    • Testando um único módulo de comportamento por um teste
    • Nomeando testes em termos de negócios
  • A única exceção são os longos testes de ponta a ponta.

Isso é tudo. Você pode aprender mais sobre o nosso curso no seminário on-line gratuito , que será realizado hoje.

All Articles