Blog > Testes ágeis
Blog > Testes ágeis
Embora cada envolvido tivesse suas próprias práticas e teorias preferidas, todos concordavam que, em suas experiências prévias, os projetos de sucesso tinham em comum um pequeno conjunto de princípios. Com base nisso eles criaram o Manifesto para o Desenvolvimento Ágil de Software, freqüentemente chamado apenas de Manifesto Ágil. Os valores descritos no Manifesto Ágil priorizavam:
Indivíduos e interação entre eles ao invés de processos e ferramentas;
Software em funcionamento ao invés de documentação abrangente;
Responder a mudanças ao invés de seguir estritamente um plano.
Adicionalmente, o Manifesto ágil, preconizava os seguintes princípios fundamentais:
Nossa maior prioridade é satisfazer o cliente, através da entrega contínua de software de valor;
Aceitar mudanças de requisitos (processos ágeis se adaptam a mudanças, para que o cliente possa tirar vantagens competitivas);
Entregar software funcionando com freqüência, na escala de semanas até meses, com preferência aos períodos mais curtos;
Pessoas relacionadas à negócios e desenvolvedores devem trabalhar em conjunto e diariamente, durante todo o curso do projeto;
O método mais eficiente e eficaz de transmitir informações para um time de desenvolvimento é através de uma conversa cara a cara;
Processos ágeis promovem um ambiente sustentável. Os patrocinadores, desenvolvedores e clientes, devem ser capazes de manter indefinidamente, passos constantes;
As melhores arquiteturas, requisitos e designs emergem de times auto-organizáveis, motivados e confiantes;
O termo "Método Ágil" identifica metodologias de desenvolvimento que adotam os valores e princípios do manifesto ágil. Dentre os inúmeros métodos ágeis existentes, podemos destacar: Extreme Programming (XP), SCRUM, Feature Driven Development (FDD), Dynamic Systems Development Method (DSDM), Crystal Clear, entre outros.
Independente da metodologia de desenvolvimento, um dos problemas mais recorrentes no desenvolvimento de software é a alta incidência de defeitos. Software defeituosos causam:
Lentidão no desenvolvimento: Quando é relatado uma falha/problema, o desenvolvedor gasta muito tempo depurando (debugging) o código para descobrir onde está o defeito e depois para corrigí-lo. Além disso, nem sempre o desenvolvedor que escreveu a funcionalidade é responsável pela correção dos seus defeitos. E para piorar, muitas vezes as empresas atribuem desenvolvedores inexperientes para a corrigir os defeitos;
Efeitos colaterais: Frequentemente, a correção de um defeito introduz como efeito colateral outros defeitos. Isso acontece em função de vários fatores, como por exemplo: falta de experiência do desenvolvedor, falta de arquitetura no software, falta de organização nos processos de trabalho da empresa, prazos muito apertados, falta de atenção do desenvolvedor em função de exaustão por ter que trabalhar muitas noites e finais de semana seguidos, entre outros;
Custos altos: Defeitos encontrados em produção tem um custo de correção cem vezes (às vezes mil vezes) mais alto do que os defeitos encontrados durante o ciclo de desenvolvimento. Isso sem contar os custos associados a insatisfação dos clientes.
Os métodos ágeis, por sua vez, mitigam os riscos e desafios associados a uma alta incidência de defeitos por meio de testes. Teste de software é mais do que uma simples tarefa, na verdade, é o pilar de sustentação que permite a implementação de muitos princípios de desenvolvimento ágil, como por exemplo:
Entrega contínua de software de valor: Testes são a única forma de demonstrar se o software atende as necessidades do cliente (software de valor);
Aceitar mudanças: Testes dão confiança ao time para realizar mudanças sem medo de causar efeitos colaterais e instabilidade no sofware;
Envolvimento de pessoas relacionadas à negócios e desenvolvimento: Testes são descritos em uma linguagem comum a todos os membros do time. Dessa forma, todo o time compartilha o mesmo entendimento do que deve ser feito, as restrições e as definições de "Pronto";
Software funcional é a medida de progresso: Testes executados frequentemente demonstram o progresso no desenvolvimento de novas funcionalidades, assim como, se o software ainda funciona (não foram introduzidos defeitos);
Excelência técnica, bom design e simplicidade: Testes escritos antes do código induzem o desenvolvedor a pensar com mais profundidade na implementação da funcionalidade, tornando dessa forma, o código mais simples e com melhor design;
Times motivados e confiantes: Testes executados com sucesso aumentam a motivação (estamos realizando nosso trabalho corretamente) e confiança do time (estamos tomando as decisões certas);
O time reflete em como ficar mais efetivo: Testes demonstram falhas tanto no código quando no processo de trabalho (e atitudes do time), com base nas lições aprendidas durante a correção da falha, o time ajusta e otimiza seu comportamento de acordo.
Na perspectiva ágil, o teste é uma tarefa paralela e intrínseca a todas as etapas do desenvolvimento, inclusive, é uma tarefa intimamente ligada ao ato de programar. Na metodologia ágil conhecida como Extreme Programming (XP), por exemplo, o teste guia o desenvolvimento. Por meio da prática chamada TDD (Test-Driven Development), o desenvolvedor escreve o código de teste antes de escrever o código que implementa a funcionalidade. Nesta filosofia, o desenvolvedor é induzido a primeiro pensar nas regras e restrições da funcionalidade para então mapear essas regras e restrições em testes (unitários). Depois, o desenvolvedor escreve o código da funcionalidade, de forma a atender o comportamento esperado que é determinado pelos testes. Segundo Kent Beck, criador e disseminador do Extreme Programming (XP), quando o programador atinge o nível de adorar escrever testes, significa que o programador tornou-se Test Infected.
No entanto, diferente do que muitas pessoas acreditam, as técnicas de testes preconizados pelas metodologias ágeis, não são limitadas a aferir apenas o código. Sem sombra de dúvida, técnicas como o TDD (Test-Driven Development), ajudam o desenvolvedor a eliminar defeitos no código, no entanto, o código não é a única fonte de defeitos. Em função disso, é importante destacar que os métodos ágeis oferecem um conjunto bastante sofisticado de técnicas de testes para prevenir e detectar defeitos no código, requisitos, arquitetura, assim como, defeitos originados por falta de entendimento, assunções erradas, etc.
O teste ágil é caracterizado por ser uma atividade: desempenhada por todos os membros do time; que ocorre em todas etapas do ciclo de vida de desenvolvimento; através de mecanismos automatizados (quando possível); e que o ocorre frequentemente em ciclos contínuos. Nas metodologias ágeis, todos são responsáveis pelos testes. A qualidade do software é responsabilidade de todos os membros do time. Cada membro do time contribui para a qualidade do software realizando testes sob a sua perspectiva. Dessa forma, os testes ocorrem de maneira colaborativa e complementar, da seguinte maneira:
Os clientes testam sob a perspectiva da funcionalidade (estória por estória).
Os desenvolvedores testam sob a perspectiva do código (método por método);
Testes sob a perspectiva do cliente
Grande parte das metodologias ágeis expressa os requisitos dos clientes em termos de estórias informais e leves. As funcionalidades são representadas através dessas estórias que refletem as necessidades do cliente e são suficientemente pequenas para permitir que os desenvolvedores consigam implementar um conjunto delas em cada iteração (ou Sprint). Uma estória deve ser compreensível por todos os membros do time, testável e valiosa para o cliente. Testável, neste contexto, indica que toda estória deve incluir os critérios de aceitação para assegurar que a funcionalidade foi implementada corretamente e atende as necessidades do cliente.
Para atingir este objetivo, o cliente é responsável por escrever testes de aceitação (Acceptance Testing) para cada estória. Os testes de aceitação são elencados pelos clientes em função de que eles conhecem profundamente o negócio e, portanto, também conhecem os objetivos que devem ser alcançados. Os testes de aceitação descrevem de forma leve e na linguagem do negócio um conjunto de exemplos concretos de uso que servem para determinar se a funcionalidade foi implementada corretamente e atende as expectativas explícitas e implícitas do cliente.
É importante destacar que o teste de aceitação descrito pelo cliente, é um dos critérios usados para determinar se a implementação da estória foi concluída. Ou seja, a estória está "pronta" apenas quando os testes de aceitação forem executados com sucesso. Kent Beck, criador e disseminador do Extreme Programming (XP) afirma categoricamente: Estórias que não podem ser demonstradas por meio de testes, simplesmente não existem.
No que se refere a execução dos testes de aceitação, não existe um consenso absoluto, mas eles podem ser executados pelo próprio desenvolvedor manualmente, por um outro desenvolvedor, por um testador ou até mesmo pelo próprio cliente. Por outro lado, as metodologias ágeis aconselham que os testes sejam executados sempre que possível por meios automáticos para viabilizar ciclos curtos entrega e feedback contínuo. Em função disso, frequentemente os testes de aceitação são automatizados pelos desenvolvedores (ou pelos testadores) usando ferramentas especializadas, tais como:
Fitnesse: (http://fitnesse.org/);
Green Pepper: (http://www.greenpeppersoftware.com);
StoryTestIQ: (http://storytestiq.solutionsiq.com);
Robot Framework: (http://code.google.com/p/robotframework/);
O teste sob a perspectiva do cliente complementa a descrição da estória, oferecendo definições adicionais sobre o comportamento esperado da funcionalidade. Além disso, quando os testes de aceitação são automatizados, ele agem como um guardião da qualidade, alertando o time quando a estabilidade do software é violada em função de efeitos colaterais ou defeitos.
Testes sob a perspectiva do desenvolvedor
Enquanto nas metodologias tradicionais o desenvolvedor apenas escreve código, nas metodologias ágeis o desenvolvedor também é responsável pelos testes. No entanto, os testes do desenvolvedor tem o objetivo de prevenir e detectar defeitos na perspectiva do código. Ou seja, o desenvolvedor deve garantir a qualidade de cada unidade do código individualmente. Unidade, neste contexto, deve ser entendida como o menor trecho de código de um software que pode ser testado, podendo ser uma função ou procedimento em linguagens de programação procedurais ou métodos de classes em linguagens orientadas a objetos.
Para demonstrar se uma unidade atende os seus requisitos, o desenvolvedor escreve testes unitários (Unit Tests). Para tal tarefa, o desenvolvedor escreve fragmentos de código com o único objetivo de executar isoladamente uma unidade e observar o seu comportamento e os resultados produzidos. Na prática, estes fragmentos de código, são os testes unitários.
Os testes unitários são normalmente escritos usando o mesmo ambiente e a mesma linguagem de programação utilizada para a implementação da unidade que está sendo testada. Em linhas gerais, os desenvolvedores escrevem testes unitários usando bibliotecas especializadas que fornecem um ambiente padronizado, mecanismos para apresentar os resultados da execução dos testes, etc. Dentre as bibliotecas mais conhecidas, podemos destacar:
JUnit: (http://www.junit.org/);
NUnit: (http://www.nunit.org/);
DUnit: (http://dunit.sourceforge.net/);
CPPTest: (http://cpptest.sourceforge.net/);
Embora os testes unitários não impeçam a incidência de defeitos, eles representam um mecanismo muito eficaz para detectá-los rapidamente, o que reduz o tempo gasto em depuração e correção. A adoção de testes unitários traz muitos benefícios, como por exemplo:
Testes unitários revelam os defeitos tão logo eles são introduzidos no software, o que evita a replicação do defeito em outras áreas do software;
Testes unitários apontam onde e como ocorre um defeito, reduzindo o tempo gasto em depuração;
Testes unitários são uma rede de segurança que dá confiança ao desenvolvedor realizar modificações e otimizações no software (Refactoring) sem medo de efeitos colaterais;
Testes unitários, ao contrário da documentação escrita, não perde o sincronismo com o código e são considerados uma forma mais leve de documentação;
Na metodologia ágil conhecida como Extreme Programming (XP), é recomendada a adoção do estilo de desenvolvimento chamado TDD (Test-Driven Development), onde o desenvolvedor escreve o código de teste antes de escrever o código que implementa a funcionalidade. Apesar desta prática não ser exigida por outros métodos ágeis, ela oferece muitos benefícios, como por exemplo:
Escrever testes antes da implementação induz o desenvolvedor a buscar mais detalhes sobre as características e regras associadas a estória;
Escrever testes antes da implementação é uma excelente forma de expressar claramente as intenções do que cada unidade deve fazer, e como consequência, os testes servem como documentação do comportamento esperado de cada unidade;
Escrever testes antes da implementação exige que o desenvolvedor escreva unidades mais simples e fáceis de testar. Como consequência, o código tem um melhor design.
Em resumo, independente da prática ou biblioteca de testes unitários adotada pelo time, o simples compromisso de criar testes induz o desenvolvedor a pensar mais profundamente na estória e também a escrever códigos mais simples e com o melhor design possível.
Testes sob a perspectiva do testador
Na visão teórica de algumas metodologias ágeis, não existe o papel conhecido por "Testador", uma vez que todos os membros dos times ágeis são auto-suficientes, tecnicamente capacitados e todos são responsáveis pelos testes. Pelo termo "Testador", queremos destacar um membro do time tecnicamente capacitado, com bastante experiência na área de testes e que dedica grande parte do seu tempo exclusivamente para testes. O testador contribui para o time de várias maneiras, especialmente estreitando a lacuna de comunicação entre o desenvolvedor e o cliente. Afinal, na prática, o desenvolvedor muitas vezes quer discutir somente aspectos técnicos da estória e o cliente, por sua vez, quer discutir apenas aspectos de negócio. Neste cenário, o testador atua como uma ponte permitindo que a informação seja traduzida e possa fluir para ambos os lados sem "ruídos".
Além disso, os testadores apoiam na definição dos testes de aceitação com base nas idéias vagas levantadas pelos clientes. Afinal, nem todos os clientes tem condições de escrever testes (ou pensar em situações de testes). Por outro lado, os testadores, com base na sua experiência com o uso de técnicas de testes, complementam os testes dos clientes com idéias diversas, situações negativas e testes mais assertivos. Muitas vezes, porém, os testadores também são responsáveis pela automação dos testes de aceitação usando ferramentas especializadas.
Os testadores também apoiam os desenvolvedores no desenvolvimento das estórias e dos testes unitários fornecendo idéias e sugestões ou até mesmo lado a lado desempenhando programação em par (Pair Programming). Afinal, não devemos esquecer, os testadores são técnicamente capacitados tanto quanto qualquer outro desenvolvedor do time.
Todavia, a maior contribuição do testador para a equipe é a sua visão do software como um todo. Enquanto o foco dos testes dos desenvolvedores é método por método e o dos clientes é estória por estória, os testadores focam no sistema como um todo. Sua visão sistêmica ajuda a descobrir assunções incorretas e problemas de integração entre módulos. Para descobrir esses tipos de problemas, o testador executa testes exploratórios, que é um tipo de teste manual baseado na experiência e intuição.
O teste exploratório é, na sua definição mais básica, o aprendizado, a criação e a execução de um teste. Quando se realiza um teste exploratório, normalmente o testador não tem informações muito detalhadas sobre o que vai testar ou como vai testar. O testador se baseia na sua experiência e julgamento, assim como no conhecimento que ele vai adquirindo sobre o software durante a execução do teste exploratório. A partir dessa perspectiva, podemos afirmar que o teste exploratório é uma atividade iterativa e empírica de exploração que exige idas e vindas num processo de investigação contínuo onde a intuição, a criatividade e a experiência do testador são indispensáveis para garantir a eficácia do teste. O teste exploratório, tem as seguintes características:
Não segue um roteiro rígido (segue guias e diretrizes);
É baseado em pensamento estruturado e exploração livre;
É adaptativo e flexível;
Enfoca o aprendizado em paralelo;
A execução do teste é guiada/aprimorada com base em execuções anteriores;
Exige testadores experientes;
Fornece fluxo imediato de feedback (e correção de curso);
Amplifica a cobertura dos testes (unitários e de aceitação).
O teste realizado pelo testador é considerado por muitos autores como redundante, em função de que teoricamente os testes unitários e de aceitação seriam capazes de prevenir e detectar todos os tipos de defeitos. Kent Beck, no seu livro "Extreme Programming Explained: Embrace Change", afirma: "Você não pode resolver os defeitos com apenas uma prática. Os defeitos são muito complexos e cheios de facetas e nunca serão resolvidos completamente. Algumas práticas são certamente redundantes, identificando os mesmo tipos de defeitos. Apesar dessas redundâncias serem um desperdício, seja cauteloso ao remover práticas redundantes que sirvam para alguma proposta. O preço da redundância é mais do que pago pela economia de evitar a incidência de um defeito".
Em resumo, os testadores fornecem uma linha de defesa adicional com objetivo de prevenir e detectar os defeitos precocemente. Além disso, na prática, os testadores realizam testes que normalmente são ignorados pelos usuários e desenvolvedores, tais como: performance, usabilidade, segurança, entre outros. Também devemos destacar a importância do testador em times ágeis na análise da causa raiz dos problemas a fim promover a melhoria e aprendizado contínuo.
Qualidade de software não está ligada apenas a encontrar mais defeitos, é uma questão de não introduzir defeitos. Por isso é essencial que as equipes de desenvolvimento sejam capazes de reduzir a incidência de defeitos e os custos associados a depuração e correção dos mesmos.
Neste contexto, a mudança de perspectiva em relação ao teste de software constitui umas das grandes diferenças entre as metodologias ágeis em relação a metodologias tradicionais de desenvolvimento de software. Enquanto nas metodologias tradicionais o teste é uma atividade realizada ao final do desenvolvimento por uma equipe independente, nas metodologias ágeis o teste é uma atividade comunitária feita por todos membros do time. Na visão ágil, a busca pela qualidade não é uma mera formalidade feita por alguém em algum momento, é uma filosofia de trabalho.
Afinal de contas, o teste ágil é o alicerce fundamental que tem por objetivo: guiar o desenvolvimento, induzir a um melhor design, fornecer segurança para sejam feitas mudanças e melhorias, complementar os requisitos, documentar o comportamento esperado, definir uma linguagem comum estreitando o relacionamento entre os membros do time, assegurar a integridade do software, detectar e apontar o local dos defeitos, aumentar a velocidade dos ciclos de feedback, reduzir o tempo gasto com depuração e demonstrar se o software funciona e atende as necessidades do cliente.