sexta-feira, 29 de julho de 2016

Testando código complexo do legado utilizando Fake em C#

Olá pessoal, hoje irei falar um pouco mais sobre teste automatizados.
A poucos dias me deparei com um cenário "bem difícil de testar", digo difícil pelo fato que o código que está lá não foi propicio a criar teste automatizado.

O assunto se tratava de evoluir a geração do xml da NFC-e, para validar se iria identificar ou não o consumidor na nota fiscal. Precisamente para garantir o que iria ser trabalhado, não iria acabar gerando bug, teria que haver testes automatizado tratando cada cenário.
O projeto do legado foi todo estruturado na linguagem vb.net, o objeto a ser tratado é responsável por criar as estruturas do XML das Notas Fiscais de consumidor eletrônica. 
Este objeto herda a estrutura de outro objeto, o NF-e, boa parte dos métodos são do tipo MustOverride e Overridable, permitindo que sobreponha o método da classe base. 
Como eu teria que evoluir o código da NFC-e, precisamente teria que testar todos os cenários possíveis, até mesmo os pontos onde eu não mexi, mas que poderia sofrer algum dano com a evolução.
A imagem abaixo é o método onde eu prontamente teria que evoluir: 

Como se pode ver o método utiliza variaz funções do meu objeto NFC-e como da NF-e, tendo outras funcionalidade que vem de outro objeto que a NF-e herda, neste caso a hierarquia é muito grande, dificultando muito para mim pensar como testar.
E trabalhando em par com Jonatan Waldow, pensamos em como poderíamos testar a nossa funcionalidade sem ter que mexer no objeto como um todo.
E uma ideia foi criar nosso objeto, recebendo como parâmetro determinadas funções do tipo action no construtor e criar os atributos privados no meu objeto recebendo essas funções.
Neste caso o meu objeto não necessariamente precisa conhecer o que realmente a função faz, com isso consigo pensar melhor como estruturar os meus testes, podendo criar funções e objetos Fake, simulando os comportamentos dos componentes externos.
O construtor do meu objeto ficou assim:

O teste do objeto o chamaria desta forma:

Com isso consigo testar cada ação do meu objeto.
A ideia aqui é demonstrar maneiras e técnicas, para facilitar criar os teste de unidade do meu projeto.
Pode-se dizer, mas terei que criar objetos com parâmetros do tipo action para tudo que for muito amarrado e muito difícil de testar.
Eu digo que não, até porque partir do momento que você começar aplicar este formato, novas ideias irão surgir e com isso ira ficar mais fácil pensar em como criar meu objeto com teste e determinadas ações que foi necessário tomar no legado não serão mais necessárias ou será bem melhor estruturada.

Eu particularmente acho que, quando começa-se a pensar nos testes primeiro, o código acaba ficando mais legível e de melhor manutenção. 

Outra coisa que iria facilitar muito esses cenários seria aprender um pouco mais sobre princípios SOLID, caso queira saber um pouco mais indico esse vídeo:  https://www.youtube.com/watch?v=Q2QdkiX6p_Y é muito bom garanto que irão gostar.

Abaixo será demonstrada como ficou os meus testes e meu objeto. 
Agradeço por ter lido este artigo, espero ter gostado, curtam e compartilhe, meu muito obrigado :).

Método da NFC-e utilizando o novo objeto:

Objeto convertido para gerenciamento dos dados do consumidor:



Objeto Fake:

Os testes do objeto ClienteDaNFCe:


2 comentários:

  1. Boa Santiago. Fakes podem ajudar bastante bastante nos testes mesmo.
    Tem alguma contra indicação? Algum problema que você vê com uso de fakes?

    ResponderExcluir
    Respostas
    1. Para projetos novos eu não acho saudável usar objetos Fake, já para iniciar a criar teste no legado e não perder muito tempo refatorando todo o objeto ai é legal. Até porque você pode atuar em um ponto específico e entregalo todo testado.

      A usabilidade de objetos fake não vejo tanto problema, até porque você está esperando um objeto tipado agora para parâmetros do tipo action dependendo da quantidade de parâmetros que seu objeto está esperando deste tipo, dai já vejo problema, uma ação a ser tomada neste caso é avaliar a dependência do seu objeto se o caso criar classes responsável por ação obs: classes responsável por consulta de dados outra para persistência em banco outra para regras de negócio e assim vai.

      Espero ter ajudado, obrigado por perguntar.

      Excluir

Jonathan Dias Campos Santiago. Tecnologia do Blogger.