Testes unitários com .NET Core: Mocking com NSubstitute

Aprenda a como utilizar a biblioteca NSubstitute em seus testes unitários nesse artigo!

Escrever testes unitários é uma prática comum em projetos onde se existe uma preocupação maior com a qualidade. Eu escrevi uma série sobre testes unitários aqui.

No terceiro artigo da série, foi apresentada a biblioteca Moq, bem como um exemplo de seu uso na escrita de um teste unitário. Ela foi utilizada para realizar a substituição de implementação em interfaces de dependências externas, ou simplesmente para criação de mocks.

Porém, existem uma outra biblioteca amplamente utilizada no mercado, chamada NSubstitute, e que será abordada neste artigo. Também utilizarei o framework de testes xUnit.

Código-fonte aqui.


Quer ser notificado sobre os próximos artigos, lives semanais, eventos e treinamentos? Entre no canal LuisDev no Telegram!


Introdução

Pelo tema de inversão de dependencia e mocks terem sido abordados em detalhes nesse artigo, não me estenderei muito nesses conceitos. Mas para lembrar:

  • Princípio de Inversão de Dependência: princípio do SOLID que diz respeito a que um módulo de alto nível não deve depender de um módulo de baixo nível. Na prática, classes não devem depender de implementações, e sim de interfaces. Quando a implementação for alterada, considerando que as classes dependam de interfaces dessas classes concretas, alterações não seriam necessárias.
  • Mocks: são objetos que simulam o comportamento de objetos reais. Podem definir retornos específicos em seus métodos, de maneira que a classe a consumir eles nem note que algo foi alterado.

Assim como o Moq, o NSubstitute permite criar objetos baseados em interfaces, e definir contratos de retorno determinísticos. Por exemplo, consigo definir que um método de uma interface de Repositório retorne uma lista fixa, ou que retorne uma exceção quando invocado.

Abaixo eu listo e descrevo brevemente os métodos principais do NSubstitute.

  • Substitute.For<T>: permite a criação de um objeto substituto de tipo T, onde T ou deve ser uma interface, ou com classes e seus membros que permitam override.
  • Método(a, b).Returns(c): define o comportamento de método Método, com os parâmetros a e b, que retornaria o valor c.
  • Received().Método(a, b): verifica se o objeto substituto recebeu uma chamada do método Método com os parâmetros passados a e b.
  • DidNotReceive().Método(a, b): verifica se o objeto substituto não recebeu uma chamada do método Método com os parâmetros passados a e b.

Passo-a-passo da implementação

Passo 1 – Criando os projetos

Primeiramente, crie um projeto de Biblioteca de Classes (.NET Core). Nesse exemplo, ele é chamado de BlogApp.

Criando um projeto de Biblioteca de Classes (.NET Core)

Em seguida, crie um projeto de Testes Unitários com xUnit (.NET Core) no Visual Studio 2019, ou via .NET CLI. Nesse exemplo, ele é chamado de BlogApp.UnitTests.

Criando um projeto de Testes do xUnit (.NET Core)

No projeto de testes instale o pacote NSubstitute. Isso pode ser feito via Gerenciador de Pacotes do Nuget.

Inslando o NSubstitute via gerenciador de pacotes Nuget

Ou via .NET CLI.

dotnet add package NSubstitute

Passo 2 – Implementando a funcionalidade

No projeto BlogApp, agora serão definidas duas interfaces correspondentes a um serviço e um repositório, chamados respectivamente de IPostService e IPostRepository. Também é criada a classe que implementa o IPostService. Apenas um método é implementado, o Create, que recebe dois campos de texto: title e content.

Para melhorar a visibilidade disso, vou separá-las em duas pastas, chamadas Services e Repositories.

Logo abaixo estão o serviço e sua interface.

Implementação do PostService

O método Create realiza uma chamada para o método Add do repositório, que por sua vez tem em sua assinatura o tipo de retorno Post, que é um objeto do domínio, e então retorna esse objeto Post obtido (poderia ser uma ViewModel, mas vamos simplificar aqui).

Geralmente já se enviaria o objeto do domínio via parâmetro para o método do repositório, mas nesse exemplo eu quero verificar os parâmetros enviados ao método da dependênca (no caso, o de repositório) utilizando o NSubstitute.

Interface IPostService

E a interface do repositório (cuja implementação vai ser substituída com NSubstitute), bem semelhante ao do Service por ser um exemplo simples.

Passo 3 – Escrevendo o teste unitário

Com o código a ser testado devidamente implementado, é criada uma classe de teste, no projeto BlogApp.UnitTests, chamada PostServiceTests. Seguindo o padrão AAA (Arrange, Act, Assert), e o padrão de nomenclatura Given_When_Then, crio o método de teste abaixo.

Implementação de teste unitário usando xUnit e NSubstitute

Note o uso dos métodos que listei na Introdução sendo utilizados.

Passo 4 – Executando os testes

Executa-se o teste via Visual Studio 2019, ou .NET CLI.

Executando o teste unitário

Sucesso!


Livros sobre Testes Unitários

Assim como comentei neste artigo, onde indiquei 3 livros essenciais para desenvolvedores .NET, os livros seguem sendo uma ótima fonte de informação. Sendo assim, decidi deixar indicação de livros sobre o tema.

Test Driven Development: By Example, Kent Beck

Livro escrito pela lenda Kent Beck, criador do Extreme Programming e Test-Driven Development, e um dos signatários originais do Manifesto Ágil. Livro fantástico sobre o tema, para quem quiser se aprofundar no assunto.

O livro pode ser encontrado aqui, em formato físico.

Test-Driven Development: Teste e Design no Mundo Real com .NET, Casa do Código

Test-Driven Development: Teste e Design no Mundo Real com .NET por [Mauricio Aniche]

O livro pode ser encontrado aqui, em formato físico ou digital.

The Art of Unit Testing: With Examples in C#, Roy Osherove

Com prólogos de autores reconhecidos mundialmente como Michael Feathers e Robert C. Martin, este livro também é uma leitura altamente indicada para aqueles que querem se aprofundar em testes unitários.

O livro pode ser encontrado aqui, em formato físico.


Inscreva-se na lista de espera do Método .NET Direto ao Ponto, um treinamento completo sobre C#, APIs com ASP.NET Core e Microsserviços:  Inscreva-se aqui.

São quase 200 vídeo-aulas sobre temas como C#, ASP NET Core 5, EF Core, CQRS, Clean Architecture, Autenticação e autorização com JWT, Testes Unitários, além de mini-cursos em Microsserviços, Performance em .NET, ASP NET Core e Azure, Docker, Carreira Internacional em .NET, e mais.


Conclusão

O artigo apresentou, tanto de maneira teórica quanto prática, o pacote NSubstitute junto com suas características e um exemplo de aplicação. Caso queira saber mais sobre o NSubstitute, indico olhar a sua documentação.

O NSubstitute se posiciona como uma ótima alternativa ao Moq em projetos tanto de pequeno, quanto de grande porte, que utilizem a prática de escrita de testes unitários.