C# - Testes de Unidade com métodos private
Hoje veremos como realizar testes de unidade com métodos private na linguagem C#. |
Um método privado é um método de classe que só pode ser chamado de dentro da classe declarante. Se você tentar acessar um método private de fora da sua classe, seu código simplesmente não compilará.
Certamente, se você trabalha com projetos que requerem controle de qualidade, você teve que apresentar um projeto de teste que envolve testes de unidade.
Nesse caso, você provavelmente teve problemas ao tentar testar um método que não é público.
Acessando o método privado com Reflection
Uma forma de contornar este problema é usar Reflection.
Um programa pode olhar para os metadados de outros assemblies ou de si mesmo, enquanto ele está executando. Quando um programa em execução olha para seus próprios metadados, ou de outros programas, a ação é chamada de Reflection.
Nota: Os metadados são informações sobre os dados, ou seja, informações sobre os tipos, o código, assembly e assim por diante - que é armazenada junto com seu programa.
Dessa forma, Reflection é o processo pelo qual um programa pode ler seus próprios metadados. Um programa que faz Reflection sobre si mesmo, extrai metadados de sua montagem e usa estes metadados ou para informar ao usuário ou para modificar o seu próprio comportamento.
Usando Reflection temos a capacidade de ler metadados em tempo de execução e assim é possível descobrir os métodos, propriedades e eventos de um tipo, e a seguir invocá-los dinamicamente; podemos também criar novos tipos em tempo de execução.
Usar Reflection
pode ser uma alternativa para resolver o problema pois com
Reflection podemos obter informações sobre um método e até mesmo invocar
o método e com este recurso podemos também chamar um método privado em uma
classe.
Tomando como base o código da classe MinhaClasse
abaixo:
public class MinhaClasse { private string _nome { get; set; } private string _email { get; set; }
public MinhaClasse(string nome, string email) public string MeuMetodoPrivado(string _nome) return this.MeuMetodoPrivado(_nome, _email); private string MeuMetodoPrivado(string nome) |
E a classe FatouInformarNomeException() que trata a exceção:
public class FaltouInformarNomeException : Exception { public FaltouInformarNomeException() : base("Faltou informar o nome") { } } |
Podemos acessar o método privado MeuMetodoPrivado() podemos usar o seguinte código:
typeof(MinhaClasse)
.GetMethod("MeuMetodoPrivado", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(new MinhaClasse(), null);
Usando o recurso em um teste de unidade
Parar poder o recurso Reflection mostrado acima em um teste de unidade precisamos inserir algumas coisas como o nome do método, o tipo, uma instância e os parâmetros.
Vamos incluir na solução um novo projeto de testes usando o xUnit e no projeto vamos incluir uma referência a FluentAssertions. (Também não esqueça de incluir uma referência ao projeto principal no projeto de teste.)
A seguir no projeto de teste vamos usar a conhecida função Activator.CreateInstance e buscaremos seus métodos e propriedades usando Linq, em seguida, invocaremos o método para testar com o conhecido método Invoke.
Assim vamos definir o código abaixo no projeto de Testes de unidade - TesteProject2:
using FluentAssertions; using System; using System.Linq; using System.Reflection; using Xunit; namespace TestProject2 Type type = typeof(MinhaClasse); MethodInfo method = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) //Act //Assert |
Executando o projeto no Test Explorer teremos o resultado do teste conforme abaixo onde acessamos o método privado da classe MinhaClasse:
Vimos assim como testar um método privado.
Afinal , devo
ou não devo testar métodos privados ?
Em primeiro lugar os métodos private são privados. Eles não devem ser invocados
fora da classe declarante. Mas vamos apenas dizer, para fins de argumentação,
que esse é um problema semântico que não se aplica aos testes de unidade. Mesmo
se esse fosse o caso, você ainda não deveria realizar testes de unidade em
métodos privados.
Veja, o problema com os testes de
unidade neste cenário, é que seus testes de unidade serão frágeis. Eles vão depender de muitos
de detalhes de implementação que podem e irão mudar.
Você pode encontrar alguma reutilização para um método privado ou decidir
refatorar a classe para torná-la mais simples. Ao cobrir esses métodos privados
com vários testes, você terá muito mais código para alterar simplesmente porque
os detalhes de implementação mudam.
E estamos conversados.
"Porque todos
devemos comparecer ante o tribunal de Cristo, para que cada um receba
segundo o que tiver feito por meio do corpo, ou bem, ou mal."
2 Coríntios 5:10
Referências:
C# - Entendo o I/O na plataforma .NET
C# - Fluxo assíncrono ou async streams
C#- Apresentando Streams assíncronos