Um dos argumentos para escrever testes automatizados é que eles podem atuar como documentação útil para um sistema. Mas o que os testes documentam? E quem vai achar essa documentação útil?
A maioria dos desenvolvedores não confia na documentação do sistema porque não há documentação suficiente para lhes dar uma ideia completa de como funciona o sistema, ou porque há muito para ler, ou porque não está bem escrita, ou porque não está atualizada, ou porque não se acredita que está atualizada.
Mas um bom conjunto de testes automatizados pode lhe dizer como o sistema funciona realmente hoje – não como alguém pensou que ele funcionava ou como eles pensaram que o sistema deveria funcionar ou como ele costumava funcionar, se alguém se preocupou em escrever isso.
Os testes não são nada mais nada menos do que a documentação executável. Ao escrever um novo código, faz sentido que ele seja documentado pela pessoa mais próxima dele: o autor. Essa é a minha razão para que os próprios desenvolvedores escrevam os testes.
Comentários em código, como “doc blocks”, e páginas wiki sempre considerados imprecisos até certo ponto . Em contraste, testes automatizados falham ruidosamente quando ficam desatualizados. Assim, no que diz respeito à documentação, testes automatizados são excepcionalmente vantajosos na medida em que (dado um servidor CI) você pelo menos tem a opção de manter a documentação atualizada sempre que ela começa a se afastar da realidade. Noah Sussman
Você pode ser capaz de usar testes como documentação, se…
Para serem úteis como documentação, os testes precisam:
- ser abrangentes – eles têm que cobrir todas as áreas importantes do código e as funções do sistema;
- ser executados frequentemente e funcionarem sempre ou, pelo menos, vezes o suficiente para dar a todos a confiança de que eles estão atualizados; e os testes têm de passar – você não pode deixar testes quebrados ou falhos;
- ser escritos para ser lidos – escrever um teste que funciona e escrever um teste que pode ser usado como documentação são duas coisas diferentes;
- estar no nível correto de abstração – a maioria das pessoas quando fala sobre testes automatizados quer dizer testes unitários.
Os testes unitários constituem a documentação do projeto que evolui naturalmente com um sistema. Leia de novo . Isso é o Santo Graal do desenvolvimento de software, documentação que evolui naturalmente com um sistema. Que melhor maneira de documentar uma classe do que fornecer um conjunto codificado de casos de uso. Isto é o que os testes unitários são: um conjunto de casos de uso codificados que documentam o que uma classe faz, dado um conjunto controlado de inputs. Como tal, esse documento de design é sempre atualizado, porque os testes unitários sempre têm que passar. Jeff Canna Testing , diversão? Sério?
É claro que mesmo os testes que são executados com frequência e passam na Integração Contínua ou de Distribuição Contínua ainda podem conter erros. Haverá testes que passam mas não deveriam, ou testes que indicam o que o sistema faz, mas o que o sistema faz não é aquilo que deveria fazer (um dos riscos de ter desenvolvedores escrevendo testes é que eles podem entender errado o requerimento e tenham o código errado, e também as provas erradas). Mas, no geral , os testes que são executados frequentemente devem ser mais precisos do que algum documento que pode ou não ter estado certo em primeiro lugar e que, provavelmente, não foi mantido atualizado desde então. E, através de análise de cobertura de código, você pode pelo menos entender que partes do sistema são descritas pelos testes, e que partes não são.
Testes devem ser escritos para ser lidos
Um problema com o uso de testes como documentação é que os testes são apenas um meio para um fim – até mesmo aqueles escritos em TDD. Os testes são apenas outra parte da infraestrutura de suporte e tooling que os desenvolvedores usam para escrever código (e é tudo sobre o código). Os testes são ferramentas para ajudar os desenvolvedores a pensar sobre o código que precisam escrever (se eles estão seguindo TDD), para provar que o código faz o que deveria fazer, e para pegar os erros quando as pessoas fizerem mudanças no futuro.
Como resultado, os desenvolvedores não colocam a mesma quantidade de atenção e disciplina na concepção e implementação de testes como fazem com o próprio código. Enquanto os testes são executados rapidamente e cobrem o código (ou pelo menos as partes importantes do código), eles fizeram o trabalho. Ninguém precisa se importar muito com como os testes são nomeados ou como eles se parecem internamente. Poucas equipes fazem revisão em par de testes unitários e, mesmo assim, a maioria dos usuários só verifica para ver que alguém escreveu um teste, e não se cada teste é correto, ou se cada teste tem um nome significativo e consistente, agradável e fácil de entender. Não há um monte de desenvolvedores que entendem xUnit Test Patterns ou gastam mais tempo – ou podem se dar ao luxo de gastar mais tempo – refatorando testes. Então, vários testes automatizados não são limpos, consistentes e fáceis de seguir.
Outra coisa que torna os testes unitários difíceis de seguir como documentação é a maneira como os testes são normalmente organizados. Convenções comuns para estruturação e nomeação dos testes unitários são que os desenvolvedores vão escrever uma classe/módulo para cada código de teste de classe/módulo no sistema, com métodos de teste para afirmar um comportamento específico naquele módulo de código.
Supondo que quem escreveu o código escreveu um conjunto abrangente de testes e seguiu uma estrutura consistente e bem definida e uma abordagem de nomeação, e que eles vieram com bons e descritivos nomes para cada classe de teste e método de teste, e que todos os que trabalharam no código ao longo do tempo entenderam tudo isso e tiveram o cuidado de manter tudo isso enquanto eles mudaram e refatoraram o código e mudaram responsabilidades e escreveram seus próprios testes (o que é assumir bastante), então você deve ser capaz de ter uma boa ideia do que está acontecendo dentro de cada pedaço de código seguindo os testes.
Você pode realmente compreender um sistema de testes unitários?
Mas você ainda não vai ser capaz de ler uma boa história sobre como um sistema é projetado, ou o que o sistema faz, ou como ele faz isso através da leitura de testes unitários.
Mesmo que os testes unitários sejam completos, atualizados, bem escritos, bem organizados e tenham bons nomes (se , se, se , se, se ), o acúmulo de informações construídas a partir do olhar de todos esses testes é esmagador. Os testes unitários são parecidos com metal, às vezes obscurecidos por ajustes ou outros problemas, e muito longe dos aspectos importantes da lógica de negócios ou do design.
Testes unitários incluem uma série de testes de processos de baixo nível que não têm ligação direta com as histórias. Steve Jorgensen, comentário em Unit Test As Documentation
Os testes seguem o código. Você não pode compreender os testes sem entender o código. Então, por que não ler o código em vez disso? Eventualmente, você vai ter que fazer isso para se certificar de que você realmente sabe o que está acontecendo, e porque sem a leitura do código você não pode saber se os testes foram bem escritos em primeiro lugar .
Um lugar onde o desenvolvimento de testes de baixo nível pode ser útil como documentação é na descrição de como usar uma API – desde que os testes sejam abrangentes, expressivos e “nomeados de tal forma que o comportamento que eles validam evidente”.
Um bom conjunto de testes de unidade como esse pode agir como uma implementação de referência, mostrando como a API deve ser usada, documentando detalhes de uso comum:
Se você estiver procurando por respostas confiáveis sobre como usar a API do Rails, não procure em outro lugar que não seja a suíte de testes unitários do Rails. Esses testes fornecem excelente documentação sobre o que é suportado pela API e o que não é, como a API deve ser usada, o tipo de casos de uso e os problemas específicos de domínio que guiaram a API, e também o que é mais provável de funcionar no uso da API em futuras versões do Rails. Peter Marklund, Rails Tip: Use the Unit Tests as Documentation
Mas, novamente, isso só funciona se você tirar um tempo para planejar, organizar e escrever os testes para fazer “obrigação dobrada” como testes e como documentação, (Double Duty: How to repurpose the unit tests you’re doing to help create the documentation you’re not, por Brian Button) e fazer com que seu testes sejam “tão compreensíveis quanto humanamente possível para tantos leitores diferentes quanto possível”.
Testes como documentação?
Eu gosto da ideia de que os testes automatizados podem servir como documentação – todos nós economizaríamos tempo e dinheiro dessa forma. Mas para quem é essa documentação, e como ela deveria ser usada?
Eu não conheço nenhum desenvolvedor que começaria pela leitura de casos testes a fim de compreender o projeto de um sistema. Um bom desenvolvedor sabe que não pode confiar em documentos ou imagens, ou testes, ou mesmo no que outros programadores dizem, ou em comentários no código. A única coisa em que eles podem confiar é no código.
Testes podem ser mais úteis como documentação para testadores. Afinal, é o trabalho de um testador compreender os testes a fim de mantê-los ou adicionar coisas a eles. Mas a maioria dos testadores não vai aprender muito com a maioria dos testes. Quando se trata de testes unitários, a coisa é a mesma para testadores e para desenvolvedores: testes de unidade não são úteis a menos que você entenda o código – e se você entender o código, então você deve lê-lo. Testes de aceitação de alto nível são mais fáceis de entender e mais úteis de olhar, especialmente para pessoas não-técnicas. Será mais fácil contar uma história e seguir uma história sobre o que um sistema faz através de cenários funcionais e de integração de alto nível (big fat tests), ou testes de aceitação capturados em uma ferramenta como Fitnesse. Em vez de afirmar as condições detalhadas específicas de implementação, esses testes descrevem cenários técnicos ou regras de negócio e fluxos de trabalho empresariais e outros requisitos que no pensamento de alguém eram importantes o suficiente para testar.
Mas mesmo se você seguir esses testes, não há nenhuma maneira de saber o quão bem eles descrevem o que o sistema faz sem gastar tempo conversando com as pessoas, aprendendo sobre o domínio, testando o sistema em si mesmo e… a leitura do código.
Perguntei ao Jonathan Kohl, um dos mais inteligentes testadores que eu conheço, sobre sua experiência utilizando testes automatizados como documentação:
Em 2003 e 2004, Brian Marick e eu estávamos investigando isso. Realizamos uma oficina experimental no XP/Agile Universe em 2004 com testadores, desenvolvedores e outros stakeholders do projeto para ver o que aconteceria se as pessoas que não estavam familiarizadas com o código do programa (tanto os testes unitários automatizados como o código) poderiam obter algo útil a partir de testes automatizados como documentação. Foi um fracasso total e absoluto. Ninguém obteve, realmente, algum proveito, da perspectiva de documentação, com os testes unitários automatizados. Tivemos que explicar o que estava acontecendo depois…
Marick e eu basicamente jogamos a ideia de lado depois dessa experiência . Eu desisti dessa coisa toda de obrigação dobrada. A documentação é muito boa em documentar e explicar, enquanto o código é bom em criar e executar o programa. Eu vou para a ferramenta certa para o trabalho agora, em vez de tentar conceitos de sobrecarga.
Resumindo, eu não acho testes úteis como documentação. Quando bem feitos, eu os acho úteis como exemplos de implementação de interfaces etc., quando eu sou novo para um sistema, mas nada substitui um documento bem escrito, especialmente quando combinado com um brainstorming cara-a-cara e explicações .
Há uma série de benefícios para testes automatizados, especialmente quando você tem um bom conjunto automatizado no lugar. Mas a documentação não é um deles.
***
Artigo traduzido pela Redação iMasters, com autorização do autor. Publicado originalmente em http://swreflections.blogspot.com.br/2013/06/automated-tests-as-documentation.html