Skip to content

Testes Unitários: do Mock ao Arrange Act & Assert #4

Description

@marciomonzon

Introdução

Com a alta na demanda de novos sistemas de informações e estes requerendo a implementação de regras de negócio, não há duvidas que as entregas precisam ter qualidade técnica. Para maximizar a qualidade delas, ou seja, do código desenvolvido, existe um tipo de teste denominado Teste de Unidade.

Veremos nas próximas seções deste artigo um pouco da teoria dos testes de unidade, também conhecido como testes unitários, e também aprenderemos a implementar um padrão conhecido como AAA (Arrange Act Assert), o qual tem como objetivo estruturar e organizar os testes em questão.


1. Testes de Unidade

Testes de Unidade ou Unitário é um teste responsável por cobrir ou validar uma unidade do código, por exemplo, um método de uma classe específica. Esses métodos retornarão um resultado e o teste verificará se é o resultado esperado. [VALENTE, 2020]

A seguir, um exemplo de um teste unitário escrito em C# no framework de teste chamado XUnit:


  [Fact]
  public void Verificar_Tamanho_Maximo_Da_Senha()
  {
      int idUsuario = 1;
      int tamanhoSenhaEsperado = 8;
      var senha = usuarioService.GerarSenha(idUsuario);
      Assert.Equal(tamanhoSenhaEsperado, senha.Length);
  }

No código acima, por enquanto, é possível identificar três pontos:

A) Unidade sendo testada: Método GerarNovaSenha;

B) Retorno esperado pelo teste: tamanhoSenhaEsperado;

C) Verificação do resultado esperado com o resultado da unidade: Assert.Equal(tamanhoSenhaEsperado, senha.Length);

Para o teste ser aprovado, o resultado esperado, na variável tamanhoSenhaEsperado, precisa ser igual ao resultado retornado pela unidade testada.


Frameworks de Teste: são tecnologias construídas para a implementação dos Testes Unitários. [VALENTE, 2020]

Exemplos: XUnit, NUnit.


1.1 Benefícios e quando escrevê-los

Acredito que seja interessante abordar esses dois assuntos na mesma seção, pois na minha opinião um complementa o outro.

O principal benefício de implementá-los é o de encontrar bugs. Esta ação pode ocorrer na fase de desenvolvimento, pois assim será mais difícil que os usuários finais encontrem problemas com a versão de produção. [VALENTE, 2020].

Outro benefício importante é que os testes em questão, funcionam como uma proteção contra regressões no código. Regressões é quando há uma implementação nova ou uma modificação de uma determinada parte do código e acaba impactando no funcionamento, ou seja, aquilo que funcionava deixou de funcionar. [VALENTE, 2020]

Também, além dos benefícios citados anteriormente, enquanto estamos desenvolvendo testes unitários, estamos de certa forma, documentando o código, pois ao estudar o teste é possível entender o comportamento da unidade (classe ou método) que ele está testando. [VALENTE, 2020]

Destaquei os principais benefícios dos testes unitários e acredito que eles mesmos denunciam o quão importante é a adoção em um software desenvolvido. Além disso, não preciso dizer “quando você deve escrevê-los” os próprios benefícios já os dizem.


1.2 Mock

É praticamente inevitável falar de testes de unidade sem falar do nosso amigo Mock e o seu importantíssimo papel no desenvolvimento desses testes.

Para começo de conversa, a palavra mock é uma palavra em inglês e segundo o dicionário Cambridge ela possui mais de um significado, e o que mais se encaixa para o nosso contexto é este: “artificial, but similar to the original”, ou seja, artificial, mas similar ao original.

Se fizermos uma rápida tradução no Google, encontraremos o seguinte resultado:



Mais uma vez, o que mais se encaixa no nosso contexto é: falso ou simulado.

Em termos técnicos, dentro do ambiente de testes de unidade, “mockar” significa simular o comportamento de uma dependência. Esta dependência pode ser, por exemplo, uma interface injetada na classe do método que precisa ser testado.


Existe alguma ferramenta de Mock? Para a nossa alegria, sim! Você não precisa criar um projeto mega mirabolante chamado “Mock”, alguém já fez isso por você, e felizmente, existe mais de uma opção para a plataforma .NET, e segue os que eu conheço:

Moq e Rhino Mocks.


Você pode estar se perguntando, “por que mockar? Faça o teste com todas as dependências, isso é desnecessário”. Veja as imagens abaixo e eu te explico o motivo:

A) Preciso testar o método chamado “GerarNovaSenha” da classe UsuarioService;



Método que precisa ser testado.


B) O objetivo do teste é o resultado da regra de negócio, ou seja, gerar uma nova senha do tipo GUID. Portanto, a dependência com o repositório chamado _usuarioRepository, não é importante no atual contexto.

C) Vimos no item B que temos uma dependência desnecessária para o resultado e portanto, devemos aplicar um mock nela no nosso teste, como exibido na imagem abaixo:



A Dependência precisa ser mockada.


D) Ao mockar a dependência citada, o framework vai simular o comportamento dela, e assim, evitando um bug no seu teste. Portanto, caso você opte por não aplicar o mock, quando o teste atingir a chamada do repositório no método sendo testado, ocorrerá uma exception e seu teste falhará.

D.1) Além de aplicar o mock, você precisa informar ao framework qual método da dependência ele precisa simular, e isso é feito através do “Setup”. Nessa programação, informamos o método para simular com seus parâmetros, que podem ser simulados ou não, e o retorno desejado com o “ReturnsAsync”, que também pode ser algo simulado ou não.



Informando qual método precisa simular, seu parâmetro e o retorno esperado


D.2) Como no contexto desse teste não é importante o comportamento do _usuarioRepository, informei qualquer parâmetro e esperei qualquer retorno, usando a sintaxe It.IsAny.

D.3) Usei o “ReturnsAsync” porque o meu método GetById é assíncrono, portanto o seu retorno será assíncrono.


É importante destacar que, em muitos casos, você precisará do retorno do método “mockado” ou precisará enviar determinados parâmetros para esse método, pois isso implicará no resultado esperado pelo teste. Exemplo:



Método com a validação do e-mail.



O Retorno no Setup está chamando um método e este será o retorno simulado esperado.



Depurando o teste.



Dá uma olhada no e-mail que veio! Deve jogar uma exception.



O Teste passou, porque o Assert já esperava a exception, conforme mostram as setas.


Espero que com essa pequena introdução do conceito de Mock, você possa ter conhecido e entendido um pouco mais sobre esse nosso amigão dos testes unitários.


2. Padrão AAA: Arrange, Act e Assert

Dificilmente um desenvolvedor de software não passe pelo amargo e doce caminho dos códigos sem Clean Code, organização e estrutura. Saiba que isso acontece nas melhores famílias.

Nós, profissionais do código de máquina, temos a obrigação de “codar” o mais “clean code” possível e nisso está incluso os Testes de Unidade.

Existem técnicas para deixar a estrutura dos seus testes mais organizadas, mas gostaria de destacar uma muito conhecida, o padrão Arrange, Act e Assert, ou melhor AAA.

Antes, vamos conhecer os significados:

A) Arrange → Organizar

É onde ocorre a inicialização dos objetos e a definição dos valores dos dados que serão passados para a unidade que será testada.

B) Act → Agir

É a seção onde o teste da unidade ocorre, utilizando os dados e objetos declarados na seção Arrange

C) Assert → Declarar

É a última seção, porém não é a menos importante!. É onde verifica se a ação do método testado tem o comportamento esperado.

Fonte: https://docs.microsoft.com/pt-br/visualstudio/test/unit-test-basics?view=vs-2022


2.1 Exemplos do AAA

Na imagem abaixo, temos um exemplo da organização e aplicação do padrão. Note que foram colocados comentários pois fazem parte do uso desse padrão.



Na próxima imagem, uma versão ainda mais organizada:



Uso de constantes e trechos abstraídos.


Em alguns casos, é possível juntar o Act e o Assert em uma única linha:



Act e Assert na mesma linha.


No caso da imagem acima, está sendo feito a execução do teste da unidade e logo após a verificação do retorno com o Assert.ThrowsAsync (Uma exception como retorno esperado).


Eu disse acima que os comentários fazem parte do padrão, porém, particularmente, após a aplicação e organização, esses comentários podem ser removidos, pois não é recomendável ter comentários em um código, pois podem ficar obsoletos. Tome cuidado com isso!


Conclusão

Espero que através desta introdução sobre os assuntos abordados neste texto, eu tenha conseguido conscientizar os leitores sobre a grande importância da aplicação de testes unitários. Preocupe-se, de uma maneira saudável, com a qualidade do seu código e das suas entregas, pois o cliente precisa estar satisfeito e também algum dia alguém fará manutenção nele.

Obrigado e até a próxima!

Márcio C. Monzón


Referências Bibliográficas

https://docs.microsoft.com/pt-br/visualstudio/test/unit-test-basics?view=vs-2022 . Acessado no dia 29/07/2022.

VALENTE, Marco Tulio. Engenharia de Software Moderna: Prinípios e práticas para desenvolvimento de software com produtividade. 2020.

Cambridge: International Dictionary of English

Artigo Original: https://medium.com/@marcio.pcmonzon/testes-unit%C3%A1rios-do-mock-ao-arrange-act-assert-2c5f29bd304c


Sobre o Autor

Márcio C. Monzon é Desenvolvedor de Software na Programmers Beyond IT. Pós Graduado em Práticas de Metodologias Ágeis e Bacharel em Sistemas de Informação. Um profissional que está em constante aprendizado e defende um desenvolvimento de software sustentável e com qualidade.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

5 MINTempo de leituraC#INICIANTEArtigo de leitura fácil por qualquer profissional

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions