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:


quarta-feira, 20 de julho de 2016

Testando código legado utilizando Mock em C#


Olá pessoal, como tinha dito na postagem anterior, hoje irei falar um pouco como utilizar Mock em C# em testes unitários.

Irei utilizar um código legado em vb.net da empresa onde trabalho e converte-lo para C# e criar os devidos teste. Para testa-lo irei mockar os dados.

O exemplo utilizado é um código em produção que apresentou erro  foi aberto um Bug para correção.
Para garantir que a correção que eu iria implementar não ocasionasse outro erro, foi extraído o código legado para um objeto em C# e testar todos os cenários possíveis.

A imagem abaixo é o método do legado que foi convertido:

Está imagem era do legado, responsáveis pelo carregamento das parametrizações em cache do servidor:

Como visto na primeira imagem, o erro ocorria pelo fato que o parâmetro "CadastaroContaContabilDeClienteAutomaticamente" estava desativado, neste casso iria ocorrer o erro pois a variável "codigoDaContaContabilPadrao" tinha como valor padrão o "0", nisso ao consultar os dados pelo código da conta contábil iria retornar  um valor nulo, como não tinha essa validação era retornado uma exceção.

Visto que temos varias propriedades em vb.net, tendo como fazer vários cenários de teste, mais ai que vem "como que vou testar isso"? 

Vamos começar pelo simples, criar um objeto em C# com o intuito de fazer a "mesma coisa que este método faz", só que com outra visão.

Para facilitar os teste fiz o seguinte, criei  um objeto responsável por gerenciar os parâmetros e outro para fazer o que eu quero.

Até ai blz, mais e os teste e os mock?, certo para mockar eu preciso mudar a forma que os dados estão chegando e outra, terei que mudar essa busca de dados.

Para facilitar  a criação neste teste e em outros, posso criar um objeto responsável por fazer as buscas dos dados e criar uma interface do mesmo. Porque no momento que meu objeto não ter mais esta dependência e precisar somente de uma assinatura do objeto sendo a sua interface, irá facilitar muito a criação dos teste de unidade, porque assim eu consigo mockar os dados retornando o que eu querer do meu mock.

Um exemplo:

No exemplo acima eu instanciei o Mock assinando o tipo do meu objeto que quero mockar,
e inseri algumas regras: 
  • Ao chamar o método "BuscaMassaDeDados" e o parâmetro solicitado for "ConfiguracaoStoreProcedure" retorne este valor.
  • Ao chamar o método "BuscaMassaDeDados" e o parâmetro solicitado for "ConfiguracaoParaBuscaDeDados" e o nome da tabela for "t0151" retorne este valor.

Pode-se fazer muitas coisas com mock, você pode implementa a regra para retorno de dados para cada situação.

No meu caso, já tenho um objeto para consulta de dados e sua interface, sendo assim meu objeto refatorado irá pedir em seu construtor a interface do meu buscador de dados, já no caso do outro objeto responsável pelo controle dos parâmetros em cache  nomeado de "ParametrosContaContabilClienteFornecedor" também viria no meu construtor como parâmetro para preenchendo os atributos privados do meu objeto.

Ficando assim:

E o objeto ParametrosContaContabilClienteFornecedor ficaria assim:

Não deu para ver na imagem mais em seu construtor ele pede somente o código da empresa, que ao utilizar o atributo publico deste objeto ele ira fazer a consulta em cache no mesmo formato que fazia anteriormente no legado.

Olhando a imagem vocês irão ver que cada atributo publico do meu objeto tem vários teste, os teste deles são parecido com este:

Não tem segredo, não tem mock, simplesmente é um teste para validar o estado do meu atributo, até porque eu troco o valor do cache antes de obter o valor do atributo.

Os teste criado foram mais para validar o comportamento de cada atributo, ao realizar a trocar dos valores do meu cache.

Até porque quando se fala em cache de servidor ficamos meio com um pé atras, aquela "velha história, ta com erro, limpa o cache" quem nunca disse isso :).

O objeto final ficou assim:


E os teste ficaram assim:

Totalizou oito teste somente deste objeto. 
Como se pode ver no objeto tenho um método que retorna um outro objeto populado.
Tem o método que retorna um mock  do objeto "BuscadorDeDados", é um mock simples que ao executar o BuscaRegistro do meu objeto utilizando a parametrização ConfiguracaoParaBuscaDeDados, até porque o meu método tem mais de uma sobre carga.
Deve-se retornar os dados da contaContabilPai se a mesma não estiver nula.
Essa validação foi imposta pelo fato de se eu passar uma tabela vazia para validar no meu objeto deve retornar "null", não pode ocorrer uma exceção do mesmo formato que era no legado.

Já neste caso aqui: 

Eu quero validar se os dados da tabela como parâmetro para o objeto, retornou do jeito que eu quero, retornou com os dados corretos.

O legado ficou assim:

E assim:

Não é o cenário mais lindo do mundo, mais me da a certeza de garantia do resultado deste objeto, sabendo que oque está sendo retornado é o esperado.

Os teste criado para essa operação cobril todos os cenários possíveis.
No TDC que participei neste ano de 2016 em SP, ouvi na palestra de teste uma coisa muito importante. 

"Teve casos de empresa que decidiu em impôr a todos os programadores, que tudo que ia ser feito tanto como evolução quanto correção, teria que ser criado testes automatizados cobrindo aumentando a cobertura de teste."

Até a e tudo lindo, mais só que alguns programadores estava utilizando isso de má vontade.
"Criava se os teste passava o coverage e olhava se aquele objeto estava 100% coberto". 

Isto não é uma pratica muito saudável até porque 100%, "não quer dizer que está tudo testado".

Até porque, os teste criado pode não estar cobrindo todos os cenários importantes, "como alguma regra de negócio importante" isso provavelmente iria ser encontrado pelo cliente e retornaria como Bug porque não?.

Por este motivo eu pessoalmente adotei o seguinte quesito, o teste que estou criando vai cobrir que cenário?, "qual o valor desse teste para o produto?".

Por que se usa tempo e tempo é uma das coisas mais valiosa hoje em dia.

Então temos que pensar em tudo que fazemos e iremos fazer, se isso vale a pena ser feito se vai agregar valor.

Bom para finalizar,

Esse artigo foi mais para falar de como testar coisas pequenas como a correção de um Bug do legado, converte-lo e teste-lo. Uma das coisas que já ouvi falar muito é principalmente em correção é que "a correção é boboca não compensa criar teste, até porque converte ele vai dar trabalho". Blz mais quem vai garantir que essa correção não gerou outro bug?

Falei do básico de mock e teste unitário, isso é apenas um pingo de água no oceano do que pode ser feito, posso falar mais sobre, mais a frente de como criar um projeto do zero todo testado e como mockar tudo sem a necessidade de criar um teste de integração que é mais pesado e mais lento.

Então é isso obrigado, espero ter ajudado em alguma coisa, até mais....

terça-feira, 12 de julho de 2016

Boas vindas


Boa tarde pessoal, sou Jonathan Dias Campos Santiago.
Sou Analista Desenvolvedor na empresa ConecSotf Tecnologia Ltda - http://www.conecsoft.com.br.

O intuito deste blog é compartilhar um pouco dos meus conhecimentos como programador.

Em breve falarei sobre como trabalhar com Mocks em .net. Vejo que é um dos assuntos bem recorrente atualmente, por este motivo irei demonstrar um pouquinho de como utilizar essa ferramenta magnifica nos testes automatizados.
Falarei também de Entity Framework core 1.0, scrum, desenvolvimento ágil e outras novidades.



Jonathan Dias Campos Santiago. Tecnologia do Blogger.