Práticas XP ajudando na efetividade do teste de software

Muita gente que me conhece sabe como sou um evangelista dos processos tradicionais como RUP, EUP, UP e MBASE e de modelos de qualidade e otimização dos processos organizacionais como CMM, CMMi, das ISOs entre vários outros modelos, metodologias e normas, que às vezes são conhecidas como pesadas, burocráticas, com pouco valor e pouca aplicabilidade, mas, como sou evangelista sempre digo que ir contra RUP/MBASE é ir contra Engenharia de Software.

Não existe verdade absoluta, falar que RUP é burocrático é imaturidade, assim como falar que SCRUM ou XP é desorganizado também é.

Mas hoje vou falar um pouco sobre como vejo o potencial dos princípios ágeis e como podemos usar algumas das técnicas inspiradas no XP para nosso dia a dia, aumentando a efetividade dos nossos testes sem perder tempo ou sair dos processos das nossas fábricas.

xplogo

Eu vejo o XP (assim como o SCRUM) como um conjunto de práticas, princípios e orientações que seguem uma quase “doutrina” chamada de Manifesto Ágil (Manifesto for Agile Software Development) ou Manifesto para desenvolvimento Ágil de Software.

Prezado leitor apaixonado pelo Agile, não me crucifique pelo que vou dizer, mas eu, no meu “maravilhoso mundo da Engenharia de Software”, considero o XP uma biblioteca de boas práticas para engenharia e o SCRUM uma biblioteca de boas práticas para gestão e acompanhamento de projetos, sendo que o próprio RUP também agrega essa mesma titulação no meu ponto de vista. Isso porque, um projeto é uma entidade vida,  e precisa de um sistema (processo), com caracteristicas únicas para atender as  suas necessidades.

Como toda biblioteca, podemos livremente usar e deixar de usar essas práticas em qualquer projeto, mas qualquer projeto deve ter um processo definido, caso não tenha, a chance de fracasso é muito alta.

Abaixo, um resumo de alguns princípios e regras que são aplicáveis para melhorar o teste de software. Abaixo, algumas práticas interessantes baseadas nas práticas e regras do XP:

•When a bug is found, tests are created to guard against it coming back
Para todo defeito que não for encontrado por um caso de teste, deve ser criado um caso de teste em uma suíte especial para evitar que esse defeito volte a acontecer futuramente. Essa prática ajuda a aumentar a cobertura e efetividade dos testes, além de criar um conjunto de casos de teste orientados a defeito de forma preventiva. Não gasta mais tempo do que é normalmente gasto, pois essa prática substitui a descrição do defeito pelos procedimentos de teste (passo a passo) do caso de teste, substituindo o teste de confirmação e aumentando a quantidade de testes de regressão.

•All code must have unit tests.
Sim. Se o compilador já faz a cobertura de testes sintáticos de todo o código fonte, por que não deve existir uma cobertura de todos os testes semânticos (de unidade)? Os testes de unidade são o primeiro filtro no teste do software, mas não é por isso que não são importantes. Para cada classe é interessante ter um conjunto de testes que pode ser escrito antes da própria classe e se possível pela mesma pessoa que vai implementá-la. Quando isso acontece, o desenvolvedor consegue ver detalhes semânticos que antes ele não podia ver, consegue ver possíveis erros e existe uma probabilidade maior de atender a todos os requisitos da funcionalidade. Para ajudar nessa tarefa, é interessante o analista de teste participar com o desenvolvedor da criação desses testes de unidade.

•Acceptance tests are run often and the score
Toda release que passe por todos os casos de teste Alpha devem ser encaminhadas para os testes de aceite. Diferente do XP, os testes de aceite que eu proponho nesse post não são baseados em Histórias de Usuários, são baseados em requisitos funcionais do usuário (os mesmos que dão origem aos casos de uso). São escritos testes baseados em cenários de negócio do sistema, de forma a validar os fluxos de trabalho que o sistema deve prover. Sugiro que sejam poucos testes, na linguagem do usuário, cada teste cobrindo o máximo dos requisitos do usuário, sem focar nos detalhes. Após a execução desses testes, é importante coletar o ponto de vista do usuário para futuras melhorias e examinar os defeitos registrados pelos testes, pois eles refletem as principais preocupações dos usuários, e a partir de cada uma dessas iterações dos testes de aceite, temos que repensar na forma como estamos desenvolvendo nossos casos de teste, para que fiquem mais próximos dos detalhes que causam os defeitos que os clientes reportaram. Recomendação: A regra de um caso de teste para cada defeito continua valendo aqui.

•Testing Cicle Velocity (Project Velocity)
Registrar o tempo gasto para executar cada ciclo de teste. Isso é importante para que a gerência sempre deixe um tempo inflacionado dessa base histórica, de forma a prover testes de regressão de todos os casos de teste do sistema e não somente aos casos de teste das novas funcionalidades e das funcionalidades com defeitos corrigidos. Recomendação: Aplicar também aos testes de aceite do usuário.

•All code must pass all unit tests before be released
Existe uma “cascatinha” importante relacionada a esse princípio. Para que um código seja integrado ao repositório, ele jamais pode estar com algum problema sintático, deve estar completo (totalmente implementado) e deve ter passado por todos os seus testes de unidade. Dessa forma garantimos que todos os testes de unidade tenham sido executados e que defeitos em módulos sejam minimizados. Após todos os códigos da release serem integrados, é recomendado que ao gerar a release seja executado um teste de fumaça para validar se o sistema está realmente funcionando sem problemas grosseiros nos seus fluxos principais. Somente após essas duas validações (teste de unidade e teste de fumaça do desenvolvedor) a release alpha deve ser gerada e enviada para que o analista de teste execute um ciclo de teste com todos os casos de teste. Executado esse ciclo com todos os casos de teste, são executados os testes dos cenários de negócios que serão enviados para o cliente e vários testes exploratórios. Se todos os testes até aqui passarem sem problemas ou defeitos, o cliente recebe uma release beta para avaliação.

•Integrate testing often (Integrate Often)
Não adianta testar sempre os casos de teste se os cenários de negócio do sistema não forem testados também, principalmente em sistemas orientados a processos como pregão eletrônico, loja virtual, logística etc. Para o cliente um sistema que funcione sem defeitos mas não atenda às suas necessidades de negócios não é melhor que um sistema cheio de defeitos funcionais. Os casos de teste, após executados individualmente, devem ser dispostos em sequências a atender um cenário de negócio ou os requisitos do usuário. Essa prática permite que sejam testados detalhes de cada funcionalidade do sistema em paralelo aos cenários de negócio do cliente (objetivo estratégico do sistema para a organização).

•Refactor whenever and wherever possible.
Assim como os requisitos, os casos de uso e as histórias de usuário mudam constantemente, os casos de teste também mudam, e esses são os artefatos que devem aceitar a mudança com mais facilidade. Vários eventos contribuem para mudança dos casos de teste, ou testing refactoring. Mudanças nos requisitos, mudanças nos casos de uso, melhoria identificada durante a execução etc. Qualquer evento que contribua para uma melhoria do caso de teste ou de qualquer artefato de teste deve ser aceito sem questionar. Os casos de teste devem refletir o “estado da arte” do sistema sob avaliação e devem ser sempre completos, objetivos, claros e o mais simples possível, permitindo a execução correta daquele teste. Refatoração não é um indicador de imaturidade, muito pelo contrário, para o teste de software, aceitar mudanças de braços abertos é uma demonstração de preocupação com o resultado que será recebido pelo cliente e se esse resultado está exatamente como ele espera. Outro indicador importante para mudar o caso de teste é a quantidade de defeitos que ele detecta. Quando o caso de teste não detecta defeitos a muito tempo, é interessante investigar se ele está com um nível de detalhe muito superficial ou mesmo incompleto.

•Dedicated Integration Computer
Dedicar um ambiente de testes para a implantação contínua do produto, sempre validando esse ambiente com o cliente, que deve sempre fornecer informações sobre o que acha do ambiente, sobre os recursos, características especiais etc., para que além do produto, o ambiente de teste esteja em melhoria contínua e mais próximo do ambiente real do cliente. Caso o sistema seja web e para usuários da internet, é importante que o ambiente cliente mude constantemente, exatamente ao contrário do ambiente de teste do servidor. Nesse caso a regra deve ser chamada de “undedicated Integration Computers”. Se for um portal até vale a pena pedir a várias pessoas na fábrica, com seus preferidos browsers para dar uma “navegada crítica” e enviar um feedback por um formulário no próprio portal, com as críticas e defeitos encontrados. Esse formulário deve conter um mecanismo coletando as informações de browser, sistema operacional, resolução etc., de modo transparente para o usuário. Com base nesses defeitos devem ser feitos casos de teste.

•The business analyst is always available.
Sem dúvida isso é fundamental. Penso que a pessoa mais importante para o analista de teste em um projeto é o analista de negócios / requisitos. Ele sim, pode estar no lugar do cliente e deve estar sempre disponível. Acredito que todo mundo, com exceção do Kent Beck e sua turma, sabe que cliente sempre disponível é um sonho distante na maioria absoluta dos casos, mas para suprir essa ausência, o analista de negócios deve estar sempre disponível para o analista de teste e suas dúvidas, assim como o arquiteto também deve estar disponível para testes de requisitos não-funcionais e o analista de teste para o desenvolvedor durante a correção de defeitos e testes de unidade.

Essas são práticas inspiradas no XP para melhorar nossas atividades de teste de software, sem gastar muito tempo com processos, análise de processos etc.

Outros princípios interessantes semelhantes, inspirados no agile:
Testar mais que o necessário sobre deixar dúvida na cobertura dos testes;
Cadastrar um defeito inválido sobre deixar de cadastrar um possível defeito;
Testes de regressão sobre testes de confirmação;
Ciclo de teste completo sobre testar novas funcionalidades;
Perseguir o zero erro sobre aceitar que o projeto terá defeitos.

Outras boas práticas:
•Automatizar o controle da execução dos testes e da cobertura dos requisitos pelos testes.
•Manter rastreabilidade dos defeitos para os casos de teste.
•Priorizar os fluxos com maior número de defeitos para testes de regressão.
•Modificar constantemente os casos de teste que não apresentem defeitos.

O mais mágico dessa onda chamada Agile é que qualquer uma das práticas e princípios acima pode ser aplicados em qualquer projeto, em qualquer fase do projeto, com qualquer equipe, individualmente ou acompanhadas de outras práticas, em qualquer metodologia de desenvolvimento de software, e com certeza vão mostrar resultados interessantes se usadas adequadamente.

São baratas, simples, fáceis de implementar e com um retorno muito alto na relação custo/benefício.

Fico aberto para críticas, sugestões e comentários de todas as naturezas. Obrigado :)

Inspiração e fontes:
Manifesto ágil: http://agilemanifesto.org/
Os doze princípios: http://agilemanifesto.org/principles.html

Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Camilo Ribeiro

Test Engineer at Klarna
Desenvolvedor, testador e agilista desde 2005, atualmente trabalhando na Suécia.

5 thoughts on “Práticas XP ajudando na efetividade do teste de software

  1. Primeiramente, muito legal o post e parabéns pela coragem! Afinal, falar sobre metodologias é sempre algo que costuma gerar muita confusão, e gostei do foco no Teste de Software. :)

    Eu não sou tradicionalista de carteirinha, e nem um agilista agilista xiita, mas confesso que tenho uma queda pelas práticas ágeis. :D

    Bem, meus comentários abaixo, são baseados na minha opinião, portanto, estão sujeitos à críticas. :)

    – Concordo com toda a introdução feita por você!

    – “When a bug is found, tests are created to guard against it coming back” – pra mim isso é óbvio (rs), e tal prática cabe em qualquer metodologia. Não entendi a parte que você fala que ele substitui o teste de confirmação. (ele é o teste de confirmação!?)

    – All code must have unit tests – sem dúvidas, a famosa história da janela quebrada, mas essa prática está longe de ser fácil;

    – Acceptance tests are run often and the score – pra mim histórias de usuário e requisitos funcionais tem o mesmo objetivo, só que a história costuma ser usada no lugar dos requisitos e do caso de uso. Quando é adotado BDD, os testes de aceitação são os mesmos que foram utilizando para guiar o desenvolvimento, assim como os unitários viram testes de regressão depois;

    – Testing Cicle Velocity (Project Velocity) – concordo.

    – All code must pass all unit tests before be released – é bom que passem mesmo (rs), já ouvir casos que isso é levado bem a sério mesmo na prática, ou seja, essa prática não é ficção-científica!

    – Integrate testing often (Integrate Often) – não entendi muito bem, esses testes já não são feitos utilizando a prática “Acceptance tests are run often and the score”?

    – Refactor whenever and wherever possible – concordo, mas confesso que a mudança pra gente não é tão fácil não, pois estávamos acostumados a automatizar testes apenas quando a funcionalidade a ser testada estava estável;

    – Dedicated Integration Computer – fundamental!

    – The business analyst is always available – concordo que é difícil o cliente está presente, mas tal prática só deve ser usada quando realmente o cliente não pode participar, e mesmo assim o analista de negócio precisa está 100% alinhado ao cliente, vai 99% pelo menos (rs).

    – Testar mais que o necessário – bonito falar isso, mas deve-se tomar cuidado, eu mudaria para “Testar da forma mais eficiente possível”. Pois devemos evitar desperdícios (lembre-se do Lean)

    – Cadastrar um defeito inválido – concordo.

    – Testes de regressão – discordo, “una cosa es una cosa y otra cosa es otra cosa”. O teste de confirmação existe para saber se o defeito foi corrigido, já o de regressão serve para verificar se a correção, não inseriu novos defeitos.

    – Ciclo de teste completo – com automatização isso deixa de ser um sonho. :)

    – Perseguir o zero erro – olha a cenoura aí gente! (rs). Mas concordo, só não me venha falar que o seu sistema tem zero defeitos, pois “isso non ecziste!”

    – Automatizar o controle da execução dos testes e da cobertura dos requisitos pelos testes – hoje em dia há várias ferramentas que nos auxiliam nisso; :)

    – Manter rastreabilidade dos defeitos para os casos de teste – importante!

    – Priorizar os fluxos com maior número de defeitos para testes de regressão – concordo.

    – Modificar constantemente os casos de teste que não apresentem defeitos – sem dúvidas (famoso paradoxo do pesticida).

    Agora em relação as tais práticas poderem ser aplicadas “em qualquer projeto, em qualquer fase do projeto, com qualquer equipe, individualmente ou acompanhadas de outras práticas, em qualquer metodologia de desenvolvimento de software”, não acredito muito não, pois nem todas são tão simples assim, principalmente, porque muitas delas implicam em uma mudança de atitude e cultura.

    É justamente aí que o Agile “perde” a sua mágica, não é tão fácil de implantar assim não, logicamente, que as práticas são mais simples, comparado aos princípios, mas os princípios são fundamentais. Ou seja, o ideal é que você entenda os princípios para saber o porque é necessário aplicar tais práticas, e serão tais princípios, que te ajudaram a tomar decisões em momentos difíceis. :)

    Abraços! E mais uma vez parabéns pelo excelente post!

    P.S.: Me desculpem pelo comentário tão extenso, espero que agregue alguma coisa.

  2. Em primeiro lugar, obrigado pelo comentário “tão extenso” Fabrício :)
    É bom saber que pessoas como você, estudam ainda a noite quando chegam cansados do trabalho, ainda mais quando gastam um pouco do tempo com nossos pensamentos ou pesquisas. São atitudes assim que fazem valer a pena escrever para o mundo. “Valew”

    Bom, também não sou xiita de nenhum dos lados, sou fã do “use o que for melhor”, mas reconheço que o movimento xiita de agile é um dos que mais está crescendo ultimamente, da mesma forma que os tradicionalistas ortodoxos de sempre não “morreram” ainda.

    Acho que a nossa geração Y está aprendendo a adaptar os conceitos e trabalhar com o melhor de cada metodologia.

    Os meus comentários iniciais nos posts foram bem superficiais, vou tentar esclarecer qualquer mal entendido, usando a mesma didática que apresentou no comentário:

    •Não entendi a parte que você fala que ele substitui o teste de confirmação.
    > Quando criamos esse novo caso de testes, com os procedimentos necessários para reproduzir o erro, já com os resultados esperados entradas e saídas, evitamos realizar o teste de confirmação num próximo ciclo de teste. Por exemplo, o teste que seria realizado para avaliar se o erro foi corrigido passa a ser um teste mais abrangente, visualizando a situação em que o defeito foi identificado, e não se o defeito identificado ainda existe. Reconheço que se fosse dar um nome para esse caso de teste, poderia ser chamado de “caso de teste baseado em defeito” ou “caso de teste de confirmação”, mas o importante nesse caso, é tentar abstrair do erro identificado, para a situação em que o erro aconteceu.

    All code must have unit tests
    > Pode ser e pode não ser fácil. Quando falei sobre o meu “maravilhoso mundo da engenharia de software” falo sobre uma equipe interessada na qualidade, motivada e capacitada, o que realmente não é muito fácil. Agora te pergunto se desenvolver um sistema não é complexo? Se criar casos de teste não é uma atividade complexa? O que faz uma atividade deixar de ser complicada para ser complexa é o investimento nessa atividade. Os unit tests não são um “bicho de sete cabeças” como muita gente pensa, principalmente desenvolvedores, mas uma prática como qualquer outra. Andar para a frente é complexo, mas depois de alguns anos se torna algo que nem percebemos o esforço que fazemos.

    •a história costuma ser usada no lugar dos requisitos e do caso de uso
    > Sim, as histórias e os requisitos tem o mesmo objetivo, mas acho que as histórias entram um pouco mais dentro do que o sistema deve fazer e os requisitos do que o sistema deve prover. Mais ou menos como se o requisitos fossem o “o que” o sistema deve fazer do ponto de vista de negócios e as histórias um detalhamento, entrando um pouco mais no “como” o sistema deve fazer do ponto de vista do negócio. Particularmente nunca trabalhei com histórias de usuários e mas “doido” para conhecer e trabalhar.

    •não entendi muito bem, esses testes já não são feitos
    > Sim e não. Os testes realizados no “Acceptance tests are run often and the score” são testes baseados nos requisitos, os realizados aqui são sequencias ordenadas de casos de teste, que tem um sentido semântico baseado nos requisitos, mas o nível de detalhamento requer experiência de testador. É como fizer que no teste “Integrate testing often” você testa os mesmos “cenários de negócio” que testa no “Acceptance tests are run often and the score“, mas com um nível de detalhamento muito diferente. O objetivo de um é testar o negócio, o objetivo do outro é testar em detalhes num cenário.

    •a mudança pra gente não é tão fácil
    > Inicialmente não considerei a possibilidade de automação, mas automação seria feita somente no momento em que boa parte dos requisitos estivessem “congelados”. O que acho importante frisar, é que os testes devem representar o “estado da arte” do sistema em desenvolvimento.

    •“Testar da forma mais eficiente possível”.
    > Concordo, mas quando tivermos uma dúvida sobre “testamos o suficiente?” é melhor tomar como “não, ainda podemos testar mais” do que “Acho que sim”. :)

    •“una cosa es una cosa y otra cosa es otra cosa”
    > Concordo com você, mas o que eu digo é dar preferência para executar o contexto completo do que uma particularidade. O que eu não quero que a pessoa limite-se a testar o defeito encontrado acreditando que o contexto do problema foi resolvido. O teste de confirmação é necessário, mas na minha opinião, se eu tiver que escolher entre os dois, minha escolha é o teste de regressão. ;)

    •hoje em dia há várias ferramentas que nos auxiliam nisso
    > Open Source e free inclusive, e ainda assim muita gente não usa . . . fico um pouco triste por isso, mas acho que está mudando.

    Sobre o final do seu comentário. O problema é que hoje em dia tudo é importante e tudo é prioridade, como nossa consultora Juliana Herbert diz: “Quando tudo é importante, nada é importante”. Se as aplicações citadas forem importantes para a organização, elas podem exigir, como tudo na vida, um tempo de adaptação sim, mas quando mudamos nossos conceitos e decidimos que vamos usar atividade X ou documentação Y, tudo se torna mais fácil.

    Por outro lado . . . Sei como eu as vezes sou simplista demais, e penso que de alguma forma podemos mudar as coisas de uma rapidamente se empenharmos em resolver o problema. Acho que ficou um pouco mais claro nesse post, mas vou tentar controlar isso para as próximas. :)
    Acho que você está certo, e muitas vezes as praticas acima podem ser difíceis de aplicar. Mas como são praticas, são mais fáceis de aplicar do que conjuntos de processos e ferramentas, e peço que considere o cenário acima comparado com um conjunto de processos e ferramentas novas, onde paradigmas sofrem grandes modificações e longos treinamentos são necessários. :)

    Para quem começou na área de teste sem um mentor, na famosa metodologia de teste chamada “Testa aí”, sabe como a idéia de caso de teste pode causar repulsa no começo, mas pergunte para uma pessoa que depois de 3~4 anos na vida de teste de software, se ela acha que consegue testar como se deve sem usar casos de teste. A resposta provavelmente será não. Usar caso de teste também foi a um tempo atrás como os testes de unidade são hoje. Uma coisa estranha, que podia gerar pouco valor, que as pessoas tinham medo de investir e etc., mas hoje é um padrão universal. Toda empresa com um departamento de teste ou com bons profissionais de teste tem um modo de gerenciar os testes e usar casos de teste para controlar a qualidade dos projetos.

    Fabrício, mais uma vez obrigado pelos elogios e muito obrigado pelas críticas também. Confesso que estudei bastante para pensar nesse post, e sei que muita coisa ainda deve estar errada ou fora do normal, mas meu objetivo com ele é estudar mais sobre agile para que em algum tempo possa aplicar mais no meu dia a dia e nos processos aqui na empresa, e que sem dúvida, comentários como o seu me ajudam a entender melhor esse “brave new world” que são as metodologias ágeis de desenvolvimento de software ;)

  3. Camilo,

    Muito interessante seu post e também as discussões com o Fabrício sobre o tema.
    Não sou um profundo conhecedor das metodologias ágeis, mas sempre tive muita simpatia pela idéias.
    Condordo que seja possível aplicar as práticas recomendadas pelos processos ágeis para melhorarmos os nossos testes, mas vejo uma grande dificuldade nisso quando falamos de organizações maiores, onde as metodologias tradicionais estão muito enraizadas na cultura.
    De qualquer forma, penso que boas práticas podem ser aplicadas com sucesso em vários contextos, inclusive conciliando metodologias tradicionais e ágeis, dependendo apenas do bom senso de quem as aplica.

    Abraço.

Leave a Reply