Categories
Notícias Testes

Livro promissor sobre mock objects

Steve Freeman e Nat Pryce do JMock, um dos meus projetos favoritos, estão escrevendo um livro entitulado “Growing Object-Oriented Software, Guided by Tests”. O assunto é muito bom e conhecendo os caras e os materiais que eles já publicaram (especialmente o artigo que fala sobre a experiência deles evoluindo uma DSL, baseando-se no desenvolvimento do JMock – “Evolving an Embedded Domain-Specific Language in Java”), acho que o livro promete.

O primeiro capítulo já está disponível no blog do JMock e chama-se “What’s the point of Test-Driven Development?”. A leitura é obrigatória e já dá uma pista do que está por vir.

Categories
Engenharia de software Testes

Programadores de Schrödinger

Donald Knuth deu uma entrevista para o InformIt esses dias que deu o que falar!

Como o Paulo Silveira comentou no GUJ, Knuth tem algumas opiniões controversas e polêmicas sobre testes unitários, eXtreme Programming, Open Source e programação concorrente. O Phillip Calçado também comentou o assunto, referindo-se a opinião do Keith Braithwaite, que tem ótimos pontos.

Sobre testes unitários em particular, Knuth fala o seguinte:

[…] the idea of immediate compilation and “unit tests” appeals to me only rarely, when I’m feeling my way in a totally unknown environment and need feedback about what works and what doesn’t. Otherwise, lots of time is wasted on activities that I simply never need to perform or even think about. Nothing needs to be “mocked up.”

Basicamente ele parece não acreditar em testes unitários.

O problema é que hoje em dia, além da complexidade da programação em sí, é necessário lidar com a complexidade do domínio do software, com o fato de que as empresas devem responder rapidamente às mudanças (e o software deve acompanhar), o fato de que não existem “desenvolvedores solo” mas sim equipes de desenvolvimento e por aí vai. Por isso é essencial que os softwares sejam bem testados e que esses testes sejam executados constantemente para garantir o bom funcionamento do sistema ao longo dos incrementos que serão feitos durante seu ciclo de vida. Mesmo com todas essas precauções, como bem disse o Phillip, se nos dias de hoje alguém ou alguma empresa pagasse $2.56 por cada bug encontrado nos seus programas (como faz o Knuth), provavelmente já estaria falida. Já imaginou então se não houvessem os testes como que seria?

Convenhamos, o caso do Knuth é um caso a parte. Ele está na ativa desde os anos 60 quando nossos pais ainda eram adolescentes, e possivelmente por isso tem práticas e opiniões que não necessariamente se aplicam às situações de hoje. É claro que ele merece todo o respeito por tudo que ele fez e faz pela computação, mas não acho que a opinião dele sobre práticas ágeis em especial possa ser levada em consideração ao pé da letra. E o que mais me preocupa nisso tudo é que, por ele ser um ícone da computação, as pessoas tomem tudo que ele falou como verdade absoluta e comecem a achar que testes unitários não servem para nada, quando na verdade eles são essenciais para qualquer programador profissional!

Para mim, os programadores que não testam poderiam ser chamados de Programadores de Schrödinger.

Falo isso por causa da teoria do Gato de Shrödinger. Resumindo a história, o físico Erwin Schrödinger uma vez sugeriu que se puséssemos um gato numa caixa fechada, onde a vida do gato dependesse do estado de uma partícula sub-atômica, haveria uma superposição de estados que faria com que, do ponto de vista da mecânica quântica, o gato estivesse vivo e morto ao mesmo tempo até que a caixa fosse aberta. Seria impossível determinar o seu estado até abrir a caixa! Na minha imaginação eu fico pensando no momento que a caixa é aberta e aparece um gato vivo (ou morto) o que aconteceu com o outro gato… Provavelmente ele está em algum outro universo paralelo onde todas as coisas são ao contrário (e as pessoas acham guarda-chuvas ao invés de perdê-los). Enfim, não se sabe de forma alguma o que pode acontecer.

Finalizando toda essa viagem, os Programadores de Schrödinger simplesmente não sabem o que vai acontecer quando o seu sistema entrar em produção. Pode ser que nenhum bug apareça e que eles fiquem ricos e comprem milhares de jatos particulares. Ou não.

Na dúvida, eu escrevo testes. 🙂

Categories
Agile Engenharia de software Refactoring Testes

Test infection: por onde começar?

Fala GC!

Cara, o que voce faria se entrasse em um projeto para implementar umas melhorias, mas esse projeto não tivesse nenhum tipo de teste, o código não fosse testável e você soubesse que daqui a 3 meses ia sair do projeto? Você perderia tempo fazendo refactoring, implementando testes, configurando CruiseControl e tal, ou ia simplesmente ligar o foda-se???

Isso acontece pelo menos 32409 vezes todos os dias em algum lugar do planeta.

Os desenvolvedores acostumados a programar com testes têm uma dificuldade enorme de trabalhar em aplicações que não tem testes. A primeira coisa que os desenvolvedores mais experientes fazem quando pegam uma aplicação nova é olhar a base de testes. Por alí já é possível descobrir uma série de comportamentos e detalhes da implementação do sistema, bem como as intenções de quem o programou. Mas o que você faz quando cai de pára-quedas num projeto que não tem um mísero teste sequer? Você não pode deixar esse problema para outra pessoa? É você o infeliz que tem que resolver o problema e fazer a faxina?

Minha resposta para essa pergunta é bem simples: SIM, você é o infeliz que tem que resolver o problema.

<história>
Uma vez eu trabalhava numa empresa e meu chefe me pediu para fazer um protótipo de um sistema que integrava um website com um PABX para fazer determinadas tarefas. Como era um protótipo e eu só tinha duas semanas, eu fiz ZERO testes (e a aplicação funcionava por milagre divino). Só que para o meu azar, esse protótipo era para fazer uma demonstração para um cliente, que adorou a idéia e comprou na mesma hora! Como meu chefe achava que já estava parcialmente pronto e funcionando, meu prazo para terminar era de mais quatro semanas. Duas semanas depois eu estava desesperado por não conseguir avançar na aplicação e não conseguir fazer o negócio funcionar. Aconteciam bugs estranhos, daqueles que te fazem pensar que você está na profissão errada. Todos os dias eu me arrependia profundamente de ter deixado os testes para trás. Meu chefe ficou desesperado e colocou mais um desenvolvedor para me ajudar. No primeiro dia ele me perguntou: “GC, onde estão os testes para eu dar uma olhada?”. Er.. bom… não tinham testes… E eu fiquei totalmente desmoralizado, fui humilhado, massacrado e apanhei quase até a morte.
</história>

Hoje em dia não abro mão dos testes. Se você entregar uma aplicação que não funciona, a culpa é sua! Então, faça tudo que é possível para garantir que tudo esteja funcionando.

Finalmente, respondendo o e-mail do meu amigo acima (que não posso dizer o nome porque não tenho permissão), eis algumas dicas para você não ficar em maus lençóis:

Dica número 1: faça sempre o melhor que puder! Mesmo que você ache que vai ficar 2 semanas ou 3 meses em um projeto, seu gerente pode mudar de idéia e você pode acabar ficando bem mais tempo do que isso. Então, tire essa idéia da cabeça já e comece a se preocupar com os testes. E mesmo que você com certeza absoluta só fique 3 meses, como que você vai sair de cabeça erguida e com a certeza de que o que você fez está funcionando se você não tem os testes para comprovar?

Dica número 2: conserte as janelas quebradas. Se alguém chega na sua casa e metade das janelas estão quebradas, então não tem muito problema se quebrar mais uma. Porém, se todas as janelas estiverem impecáveis, quebrar uma janela é péssimo! Siga este mesmo princípio para o seu código, não tenha janelas quebradas. Se você tiver 90% de cobertura de testes, todos eles forem impecáveis e nenhum falhar no CruiseControl, o próximo desenvolvedor que chegar se sentirá na obrigação de manter tudo funcionando da mesma forma, porque esta é a cultura do projeto. Já se todos os testes estiverem quebrados ou não houverem testes, não faz a menor diferença.

Dica número 3: não abraçe o mundo com as pernas! Não precisa refatorar a aplicação inteira de uma vez, até porque você corre um grande risco de tudo parar de funcionar e você ser demitido, além de que não vai conseguir implementar as features. Neste caso, minha estratégia seria refatorar o código na medida que precisasse implementar as features. Faria o ciclo normal de TDD: implementaria os testes fazendo refactor na implementação para torná-la testável, implementaria a feature, garantiria seu funcionamento e depois um novo refactor para deixar tudo bonito.

Dica número 4: get them Test Infected! Faça um workshop com os outros desenvolvedores do time e mostre para eles a importância de escrever testes. Ensine-os a usar o CruiseControl, JUnit, JMock, injeção de dependência e tudo mais que for necessário para que os testes aconteçam. Mesmo que você “perca” dois ou três dias de trabalho, com certeza ganhará muito mais desse dia em diante.

<piada>
Dica número 5: só por via das dúvidas, para ajudar nos momentos de fraqueza, coloque alguém para te vigiar em tempo integral. O “Dijkstra is watching” é ótimo para isso, tenha ele sempre por perto.
</piada>

Categories
Controle de qualidade Testes

Você automatiza seus testes de aceitação?

O Danilo Sato escreveu um post muito bom sobre automatização de testes de aceitação:

“Muitas equipes XP não automatizam seus testes de aceitação. Essa é uma afirmação dura, porém muito comum de acontecer. A equipe abraça TDD e testes de unidade automatizados, porém quando chega a hora dos testes de aceitação, a coisa complica. Por que isso acontece? Como melhorar essa situação?”

Testes de aceitação são essenciais e automatizá-los é extremamente desejável!

Quem acompanha meu blog já deve ter percebido que teste de software é um assunto que me interessa bastante. Ultimamente tenho trabalhado muito focado na qualidade dos softwares que entregamos na minha equipe e por isso estou constantemente explorando novas maneiras de testar ou procurando melhorar as maneiras antigas.

Nos últimos sprints temos feito da seguinte forma: o desenvolvedor que trabalhar no desenvolvimento de uma história não pode fazer testes de aceitação da mesma. Desta forma cada um sempre testa o que o outro fez (estamos usando Selenium para este tipo de teste).

Ao fim do 4o. sprint temos uma suite de testes expressiva que cobre praticamente 100% do que foi desenvolvido. Realmente percebemos que aqueles bugs extremamente simples que normalmente são encontrados em QA ou mesmo em produção foram encontrados em tempo de desenvolvimento e corrigidos com rapidez.

Rodando automaticamente estes testes são uma ferramenta poderosíssima para ajudar a garantir a qualidade da aplicação.

Recomendo fortemente a leitura do post do Danilo!

Categories
Integração Contínua TDD Testes

Mock Objects em excesso podem atrapalhar

Acabo de ler na Artima um artigo sobre o uso excessivo de Mock Objects.

Fazer testes unitários pode não ser a tarefa mais fácil do mundo quando suas classes dependem de sistemas externos que você não controla como banco de dados, webservices e qualquer outra coisa que não faz parte do seu sistema. É aí que entram os Mock Objects, que são objetos que servem para “simular” as dependências das suas classes. Eles possuem comportamento controlado e fazem exatamente o que você definir, tornando os resultados das chamadas às dependências de um código totalmente previsíveis. Sabendo que todas as dependências estão funcionando corretamente, qualquer falha que aconteça nos testes está com certeza no local (método, classe, etc) testado.

O problema é quando decide-se simular todas as dependências. Isso é um pouco controverso porque na verdade quando você está fazendo testes unitários o certo mesmo é isolar o método e “mockar” todas as dependências. Porém em alguns casos isso acaba fazendo com que o teste fique muito complexo e difícil de ser entendido e mantido.

Além disso os testes com muitos Mocks podem acabar ocultando problemas na colaboração entre os objetos. Os objetos dependentes em uma determinada situação podem funcionar diferente de como foram “mockados” e pode ser interessante utilizar os objetos reais. Mas neste caso os seus testes seriam testes de integração e não testes unitários.

Ultimamente eu tenho optado por ir pelo caminho do meio e por isso concordo quase integralmente com a opinião do Alex Ruiz. Acredito que em boa parte das vezes você não precisa criar mocks de tudo que vê pela frente.

Um exemplo real é o sistema que estou trabalhando atualmente, onde estou desenvolvendo um cliente para um webservice REST. Este cliente é bem magro e basicamente ele pega XMLs de coisas que foram processadas no servidor (webservice) e transforma em objetos Java. Para isso o cliente acessa via HTTP um determinado endereço, obtém um XML que representa uma entidade do sistema, transforma em um objeto Java e retorna o resultado. Como este cliente é muito magro e praticamente não faz nenhum processamento, na maioria dos testes a única dependência que eu “mockei” foi o XML retornado, já que a única coisa não controlada pelo meu sistema é o canal HTTP e o servidor dos webservices que pode estar a qualquer momento offline e meu teste não pode falhar por causa disso. Para fazer isso eu injetei no repositório de objetos um HTTP Client mock que sempre retorna um XML válido. Com isso o meu teste verifica se o cliente retorna objetos Java corretos considerando que o webservice está funcionando. É claro que este não é o único tipo de teste que eu faço, tenho testes mais específicos para outras funcionalidades mais importantes, como a classe que transforma objetos em XML para Java e por aí vai.

Resumindo isso tudo, acho importante analisar cada caso e ver se há necessidade de criar testes canônicamente corretos ou se opções mais simples podem resolver o problema da mesma forma.