Mocking Test no .NET Core: utilizando o framework NSubstitute

O objetivo deste artigo é descrever o uso de práticas de Mocking Test com o .NET Core, empregando para isto do framework NSubstitute.


Introdução

Nem sempre a implementação de testes de unidade será uma tarefa fácil. Dependências entre as diferentes partes de um software, a inexistência de ambientes específicos para validação e a integração com servidos externos são alguns dos fatores que podem limitar ou, até mesmo, inviabilizar este tipo de prática.

E como superar estas dificuldades? A solução nestes casos envolve a simulação/imitação de comportamentos considerados como impossíveis de se testar. Recursos conhecidos como Mocks simplificam tal processo, fornecendo meios para emular o funcionamento de um objeto e assim permitir sua validação sem grandes esforços de codificação.

Frameworks para a criação de Mock Objects dispensam a implementação de estruturas de código que seriam descartadas posteriormente. Isto acontece através de mecanismos que permitem definir o retorno de métodos, propriedades e até o lançamento de exceções dentro de classes contendo testes de unidade. Duas alternativas gratuitas para mocking na plataforma .NET são os frameworks Moq e NSubstitute.

A finalidade deste artigo é demonstrar a criação de Mock Objects em testes de unidade gerados com o .NET Core, utilizando para tanto o framework NSubstitute.


Criando o projeto a ser testado

Para implementar os projetos apresentados nesta e na próxima seção foram usados os seguintes recursos:

  • O Microsoft Visual Studio Community 2017;
  • .NET Core 1.1;
  • A versão 2.2.0 do xUnit, framework para implementação de testes de unidade em .NET;
  • O NSubstitute 2.0.2.

O exemplo aqui descrito é uma variação de um projeto baseado no framework Moq, o qual foi detalhado em outro artigo que escrevi anteriormente.

Inicialmente será criado um projeto do tipo Class Library (.NET Core) chamado ConsultaCredito, como indicado na imagem a seguir:

A biblioteca ConsultaCredito conterá os recursos empregados na interação com um serviço de consulta a crédito, utilizando para isto o número de CPF de eventuais clientes durante a realização de pesquisas. No próximo diagrama estão as estruturas a serem implementadas nesse projeto:

Na listagem a seguir é possível observar:

  • O enumeration StatusConsultaCredito, com os status esperados na interação com o serviço de consulta a crédito;
  • A classe Pendencia, com propriedades que identificam a pessoa física e suas eventuais pendências financeiras.

Dentre as situações previstas pelo enumeration StatusConsultaCredito estão:

  • O envio de um CPF inválido (valor ParametroEnvioInvalido);
  • O lançamento de uma exceção ao invocar o serviço de consulta a crédito (valor ErroComunicacao);
  • A inexistência de pendências para uma pessoa física (valor SemPendencias);
  • A detecção de pendências financeiras associadas a uma pessoa física (valor Inadimplente).

A interface IServicoConsultaCredito representa a base para a implementação do mecanismo de comunicação com o serviço de consulta a crédito, além do meio através do qual serão criados Mocks para o teste deste processo. Tudo isto acontecerá no método ConsultarPendenciasPorCPF, cujos retornos possíveis são:

  • Uma exceção, caso ocorram problemas na comunicação com o serviço;
  • Nulo, em se tratando de um CPF inválido;
  • Uma coleção com uma ou mais instâncias do tipo Pendencia, se a pessoa física em questão possuir pendências financeiras;
  • Uma coleção do tipo Pendencia sem elementos, para pessoas físicas sem qualquer impedimento financeiro.

Já na próxima listagem está a definição da classe AnaliseCredito:

  • Este tipo receberá em seu construtor uma instância do tipo IServicoConsultaCredito, a qual será empregada no acesso ao serviço de consulta;
  • A comunicação entre a classe AnaliseCredito e tal serviço se dará no método ConsultarSituacaoCPF, que foi preparado para o tratamento dos diferentes retornos ao se invocar a operação ConsultarPendenciasPorCPF de IServicoConsultaCredito.

Implementando os testes

O próximo passo agora consistirá na criação de um projeto de testes chamado ConsultaCredito.Testes. Selecionar para isto o template xUnit Test Project (.NET Core), no qual será feito uso do framework xUnit para a implementação de testes de unidade:

Acrescentar ainda uma referência à biblioteca ConsultaCredito:

E adicionar o package do NSubstitute ao projeto ConsultaCredito.Testes:

Na classe Testes foram implementadas validações para os diferentes casos de teste envolvendo o uso do tipo AnaliseCredito:

  • Quatro constantes (CPF_INVALIDO, CPF_ERRO_COMUNICACAO, CPF_SEM_PENDENCIAS e CPF_INADIMPLENTE) foram definidas, com as mesmas correspondendo aos diferentes números de CPF empregados em cada validação prevista pela classe Testes;
  • Uma instância do tipo IServicoConsultaCredito (mock) será criada no construtor de Testes, por meio de uma chamada ao método For da classe Substitute (namespace NSubstitute);
  • O Mock Object resultante será configurado, através de chamadas aos métodos ConsultarPendenciasPorCPF (que receberá o CPF específico para um caso de teste) e Returns (este último um Extension Method provido pelo framework NSubstitute, no qual será indicado o retorno esperado para cada CPF);
  • As operações TestarParametroInvalido, TestarErroComunicacao, TestarCPFSemPendencias e TestarCPFInadimplente foram marcadas com o atributo Fact (namespace Xunit), de forma a permitir que o Visual Studio identifique os métodos/casos de teste a serem executados;
  • O método auxiliar ObterStatusAnaliseCredito receberá um CPF e utilizará o Mock Object criado no construtor, a fim de obter o retorno a ser validado por cada um dos 4 casos de teste.

Executando os testes

Para executar o projeto de testes será necessário acessar o menu Tests > Run > All Tests:

Na janela Test Explorer constará o resultado da execução dos diferentes casos de teste:


Conclusão

Frameworks de Mocking Test simulam o comportamento de objetos em diferentes cenários, dispensando os desenvolvedores da necessidade de criar implementações que seriam descartadas/desativadas num ambiente de produção. O NSubstitute exemplifica bem isto, sendo que outro ponto que pesa a seu favor está no fato do mesmo exigir menores esforços de codificação quando comparado ao Moq.


Like what you read? Give Renato Groffe a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.