2. SobreDenis Ferrari GraduandoemSistemas de informaçãopelaFAESA; Arquiteto de software; Ministrapalestras e treinamentos; Consultor de negócios; MCP, MCTS (Web Applications e Distributed Applications), MCPD (Web Applications); EscreveartigosparaosportaisImasters, Linha de código e osdisponibilizatambémemseu blog. 9 anos de experiência no mercado de TI capixabaatuandocomoInstrutor, Web Master, DesenvolvedorSênior e Gerente de Projetos;
3. Objetivosdapalestra Apresentar a metodologiaágile seusvalores. Apresentar o desenvolvimentoorientado a testescomoumaalternativaaodesenvolvimentotradicional.
5. MetodologiaÁgil Desenvolvimento ágil de software (do inglês Agile software development) ou Método ágil é um conjunto de metodologias de desenvolvimento de software. O desenvolvimento ágil, tal como qualquer metodologia de software, providencia uma estrutura conceitual para reger projetos de engenharia de software. http://pt.wikipedia.org/wiki/Desenvolvimento_%C3%A1gil_de_software
6. Histórico Começou em um encontro em Fevereiro de 2001, Utah, USA. com os seguintes representantes: Extreme Programming, SCRUM, DSDM, Adaptive Software Development, Crystal, Feature-DrivenDevelopment, Pragmatic Programming, e outros; O objetivo do encontro foi discutir alternativas ao rigoroso processo de documentação necessário para o processo de desenvolvimento de software; Deu origem ao "Manifesto Ágil" assinado pelos dezessete participantes do encontro.
7. Conceitos DEFINIÇÃO:Movimento iniciado por programadores experientes e consultoresem desenvolvimento de software. PRINCÍPIOS:Indivíduos e interações X processos e ferramentas;Software funcional X documentação abrangente;Colaboração com o cliente X negociação de contratos;Adaptação a mudanças X seguir plano inicial. http://agilemanifesto.org/
8. Assinaram o manifesto: Kent Beck, Mike Beedle, Arie van Bennekum, AlistairCockburn,WardCunningham, Martin Fowler, James Grenning, Jim Highsmith, Andrew Hunt, Roland Jeffries, Jon Kern, Brian Marick, Robert C. Martin, Steve Mellor, Ken Schwaber, Jeff Sutherland; Dave Thomas.
10. TDD é uma técnica de desenvolvimento de software cujo processo é formado por pequenas iterações para o desenvolvimento de uma nova funcionalidade, começando pela implementação de um caso de teste, depois pelo código necessário para fazer o teste passar, e finalmente pela refatoração do código visando melhor acomodar as mudanças feitas. Não é um método para testar software, mas para construir software. TDD vem do conceito de “test-first programming” do XP (Extreme Programming), mas acabou ganhando tanto interesse, que hoje tem sido adotado independente do XP e das técnicas de programação ágil; Introdução ao TDD (1/2)
11. Objetivo do TDD: código limpo que funciona “Mantra” do TDD: vermelho-verde-refatorar Codifique o teste; Faça ele compilar e executar (não deve passar - vermelho); Implemente o requisito e faça o teste passar (verde); Refatore o código; Introdução ao TDD (2/2)
12. Garante a existência de testes unitários completos e atualizados, que: Eliminam o medo de alterarmos alguma coisa que funciona (testada manualmente), e acabarmos introduzindo algum problema; Nos permite utilizar refatoração (substituir uma implementação por outra equivalente) de forma muito mais agressiva devido à facilidade dos testes verificarem o resultado. Diminui a quantidade de erros por linha de código (código-fonte de mais qualidade) Testes unitários servem como especificação de como os componentes do sistema funcionam; Nos leva a produzir componentes de software mais desacoplados, para garantir o isolamento dos testes, o que acaba favorecendo o projeto do sistema. Principais Benefícios do TDD
13. Testes de Unidade; Testes de Integração; Testes de Sistema; Testes de Integração de Sistema; Testes de Aceitação; Tipos de Testes
14. A Metodologia TDD é conduzida através dos “testes do programador”. Frequentemente esses testes são chamados de “teste de unidade”, mas esse nem sempre é o caso (pode ser teste de integração). É importante destacar que não se trata dos testes de sistema (caixa preta) nem os de aceitação (feitos pelo usuário final) Tipos de Testes
15. A “Espiral da Morte” do Teste O ciclo mortal do “estou sem tempo para testar”:
16. 1. Construa testes isolados uns dos outros Um caso de teste não deve depender do sucesso de outro para funcionar; Deve ser possível executar um caso de testes isoladamente, sem executar nenhum outro; 2. Comece definindo uma “TestList” De modo geral para uma mesma classe ou método a ser testado, existirão diferentes casos de teste. Liste-os primeiro (brain-storm); Provavelmente ao longo do desenvolvimento você adicionará novos casos de teste à lista; Princípios
17. Mas o que testamos? Fluxos Condicionais (IFs, Switches, etc.) Polimorfismos Loops Operações Etc.. Princípios
18. Exemplo de “Lista de Testes” para o caso de uso “Realizar Transferência Bancária”: Realizar uma transferência normal (bem sucedida); Tentar transferir uma quantidade superior ao saldo da conta de origem; Verificar atomicidade no caso de falha de sistema antes de concluir a operação; Conta de origem inativa; Conta de destino inativa; Valor transferido menor que zero; Princípios
19. Exemplo de “Lista de Testes” para o caso de uso “Matricular Aluno em Disciplina”: Matricular com sucesso; Tentar matricular sem atender disciplinas pré-requisito; Tentar matricular sem atender pré-requisito de crédito; Tentar matricular com conflito de horário; Tentar matricular sem vaga; Tentar matricular em disciplina já cumprida; Tentar matricular em disciplina que já está matriculada (outra turma); Tentar matricular em disciplina que já está matriculada (mesma turma); Princípios
20. 3. Primeiro o Teste Oportunidade para pensar no design (projeto) das classes Controlar o escopo do que será implementado – somente o necessário para atender o teste corrente. 4. Primeiro a Assertiva É melhor pensarmos no que significa o sucesso do caso de teste antes de pensarmos no restante: Vou precisar de criar um novo método? Em qual classe? Qual será o nome dele e seus parâmetros? “Primeiro a assertiva” está para o caso de teste assim como “Primeiro o teste” está para o caso de uso; Princípios
22. 5. Dados para Teste Não escolha números mágicos se eles não tiverem um significado específico no teste. Por exemplo, se não faz diferença utilizar “1”, “2” ou “1365”, preferia “1”. Evite passar o mesmo valor para diferentes parâmetros. Por exemplo, para testar um método Operacao(int x, int y), não utilize Operacao(2,2), pois “Operacao” pode inverter “x” e “y” e o teste ainda assim passar. Prefira, por exemplo, Operacao(2,3). Dê preferência a dados do mundo real, especialmente quando você tem algum sistema legado com dados que podem ser aproveitados Princípios
23. 6. Dados com Significado Evidente Lembre que está escrevendo um teste para alguém ler, e não somente para ser executado pelo computador. Tente escrever na assertiva expressões que não só representem o valor final esperado, mas o que eles significam. Exemplo: Princípios [Test] publicvoid Testar_Fatorial_8() { Assert.AreEqual(40320, Matematica.Fatorial(8)); } [Test] publicvoid Testar_Fatorial_8() { Assert.AreEqual(8 * 7 * 6 * 5 * 4 * 3 * 2, Matematica.Fatorial(8)); }
24. Trata sobre quando escrever, onde escrever e quando parar de escrever testes. Qual o próximo teste da lista a implementar? Escolha um teste que você esteja confiante que pode implementá-lo facilmente; Não comece pelo teste mais realístico (completo), pois você será forçado a implementar um monte de coisas para atender o teste. Siga na direção “mais conhecidos” para “pouco conhecidos” Cada iteração “red/green/refactor” deve levar apenas alguns minutos. Exercício: Se você estiver construindo uma lista encadeada, qual seria seu primeiro caso de teste? “Red Bar Patterns”
25. Testes de Estudo Devemos escrever testes para componentes ou bibliotecas de terceiros que, supostamente, funcionam? Sim. Para estudar e documentar seu uso. Esse é uma forma de assegurar-se sobre como utilizar tal biblioteca de forma a obter os resultados esperados e documentar seu uso (considerando especificamente suas necessidades, e não todos os recursos da biblioteca). “Red Bar Patterns”
26. Testes de Outras Funcionalidades Sempre que uma discussão desviar do assunto principal e entrar em outras questões, essa pode ser uma hora de adicionar novos casos de teste à sua lista (para a funcionalidade em questão) e voltar para o assunto principal. “Red Bar Patterns”
27. Defeitos Reportados Sempre que um defeito é reportado nossa primeira ação deve ser escrever um caso de teste que reproduza o problema. Se isso for feito certamente o problema será resolvido. Testes de Regressão Consiste em testar novamente uma funcionalidade que foi implementada e testada anteriormente; Teoricamente, após qualquer alteração no sistema, todo o sistema deveria ser testado para garantir que essa alteração não tenha introduzido algum efeito colateral indesejável. Uma boa prática é executar testes de regressão de todo o sistema, todos os dias, à noite, e reportar os problemas encontrados para a equipe. Existem softwares para gerenciar isso. “Red Bar Patterns”
28. Técnicas mais detalhadas sobre como escrever testes. Subdividir Testes Quando um teste ficou grande demais e você está demorando muito para conseguir implementá-lo (mais de 10 min já deve te encomodar), pode ser melhor dividir o teste em testes menores até conseguir fazer o teste maior passar. MockObjects Como testar objetos que dependem de recursos externos custosos ou complexos, como bancos de dados e webservices, por exemplo? Crie uma versão falsa ou simulada do objeto (“fake”) que retorne valores constantes. Referência: www.mockobjects.com Ferramentas para .NET: NMock e RhinoMocks. “TestingPatterns”
29. Uma vez que você tenha um teste vermelho, busque torná-lo verde o quanto antes. Use os padrões que serão discutidos para conseguir isso rapidamente, mesmo que o resultado seja algo que você não aceita conviver nem por uma hora. “Green Bar Patterns”
30. “Fake it ‘til youmake it” (simule até construir realmente) Por exemplo, qual é a forma mais simples de implementar o código abaixo? A forma mas direta seria: “Green Bar Patterns” publicvoidTestarSoma() { Assert.AreEqual(5, Somar(2,3)); } publicvoidTestarSoma() { Assert.AreEqual(5, Somar(2,3)); } publicint Somar(int x, int y) { return 5; }
31. Triangulação Quando você tem dois ou mais testes, você precisa de uma implementação que atenda a todos simultaneamente. Agora a solução trivial (constante) não atende mais, e somos forçados e implementar algo mais abrangente. É claro que esse exemplo é apenas ilustrativo. Se você já tem uma implementação correta óbvia, então implemente. Senão, “fake it”. “Green Bar Patterns” Página 31 publicvoidTestarSoma() { Assert.AreEqual(5, Somar(2,3)); Assert.AreEqual(7, Somar(3,4)); }
32. Implementação Óbvia Se você consegue implementar algo diretamente, então implemente. Para que utilizar “fake” ou triangulação? Mas quando você achar que sabe implementar e se deparar com uma barra vermelha? Depois você descobre, errei aqui, e aí outra barra vermelha! Talvez seja hora de dividir o problema em problemas menores. Acreditar que você sempre vai conseguir acertar e escrever o código mais simples para o problema diretamente é exigir de você perfeição. “TestingPatterns”