A apresentação introduz o Test Driven Development (TDD) e seus princípios. Discute os benefícios do TDD, como aumentar a qualidade do software e simplificar o processo de desenvolvimento de forma incremental através de testes. Também aborda paradigmas e falácias comuns sobre TDD.
2. Quem sou Eu? Leonardo R. Aguiar (Mais conhecido como Léo ¬¬) #SouDev na #TGS (Thomas Greg) leonardo.r.aguiar@gmail.com @L30n4rdo http://leonardoRaguiar.com.br/blog/
3. Agenda do dia! Manifesto Ágil Princípios S.O.L.I.D. O que é Test DrivenDevelopment? Ciclo do TDD TDD Não é uma técnica de Teste de Software Objetos Mock e Stub Desenvolvimento “Tradicional” Desenvolvimento com TDD Benefícios do TDD Paradigmas e Falácias sobre TDD
17. Paradigmas e Falácias sobre TDD É mais demorado desenvolver com TDD Eu não sei o que testar Testar é difícil Desenvolvendo com TDD não preciso de testes O projeto está atrasado Eu não tenho tempo para testar TDD só funciona com metodologias ágeis
18. Conclusão “TDDnão é sobre testes, é sobre como utilizar testes para criar sistemas de forma simples e incremental. Isto não somente aumenta a qualidade do software, mas também simplifica o processo de desenvolvimento.” Fonte: Test-Driven Development: A J2EE Example. Berkeley: Apress, 2004.
TDD = Test-First + Design Incremental (Kent Back)TDD é um técnica de programação criada por Kent Beck, é uma das práticas da metodologia XP.TDD não é uma técnica de Teste de SoftwareTDD é uma prática para obter feedback rápido sobre o código que esta sendo criadoÉ utilizada com o objetivo de escrever código mais coeso e menos acopladoTDD é uma técnica de desenvolvimento de software guiado por testes.No TDD primeiro você escreve o código para testar uma funcionalidade, e só depois você escreve a funcionalidade.A técnica é bem simples, e consiste apenas de 3 regras, um mantra:RED– Que significa que o teste não passou.GREEN – Que significa que o teste passou.RAFACTORING – Que significa “melhorar” o código desenvolvido anteriormente.
Escreva um pequeno teste que falhe, e talvez até mesmo sequer compile inicialmente;Faça o teste passar da maneira rápida, cometendo qualquer “pecado” durante este processo;Refactoring: elimine toda duplicação e badsmellcriada para fazer os testes passarem.
Escrever TesteEscreva um teste de unidade para a funcionalidade que você pretende implementarExecutar TesteExecute o teste através de alguma ferramenta de teste unitário: MSTest, NUnit, Junit, PHPUnit (Pesquisar ferramentas)Implementar CódigoSe o teste não passou, implemente um código suficiente para o teste passar, da maneira mais simples possívelNessa etapa vale cometer alguns pecados do ponte de vista de boas práticas de programação.Refatorar?Veja se há a necessidade de fazer a refatoração. Veja se existe código duplicado, código HardCoded ou muitos desvios desnecessários ( IFs da vida)?Se for necessário refatorar, refatore e volte para a etapa de testes.
TDD não é uma técnica de teste de software, é uma técnica de desenvolvimento de software, que tem por objetivo dar feedback de maneira rápida ao desenvolvedor para ajuda-lo a deixar o código mais claro (simples), uma arquitetura coesa e pouco acoplada.Tipos ou Fases de TestesTeste de unidadeTambém conhecida como teste unitário ou teste de módulo, é a fase em que se testam as menores unidades de software desenvolvidas (pequenas partes ou unidades do sistema). O universo alvo desse tipo de teste são assubrotinas ou mesmo pequenos trechos de código. Assim, o objetivo é o de encontrar falhas de funcionamento dentro de uma pequena parte do sistema funcionando independentemente do todo.Teste de integraçãoNa fase de teste de integração, o objetivo é encontrar falhas provenientes da integração interna dos componentes de um sistema. Geralmente os tipos de falhas encontradas são de transmissão de dados. Por exemplo, um componente A pode estar aguardando o retorno de um valor X ao executar um método do componente B; porém, B pode retornar um valor Y, gerando uma falha. Não faz parte do escopo dessa fase de teste o tratamento de interfaces com outros sistemas (integração entre sistemas). Essas interfaces são testadas na fase de teste de sistema, apesar de, a critério do gerente de projeto, estas interfaces podem ser testadas mesmo antes de o sistema estar plenamente construído.Teste de sistemaNa fase de teste de sistema, o objetivo é executar o sistema sob ponto de vista de seu usuário final, varrendo as funcionalidades em busca de falhas em relação aos objetivos originais. Os testes são executados em condições similares – de ambiente, interfaces sistêmicas e massas de dados – àquelas que um usuário utilizará no seu dia-a-dia de manipulação do sistema. De acordo com a política de uma organização, podem ser utilizadas condições reais de ambiente, interfaces sistêmicas e massas de dados.Teste de aceitaçãoGeralmente, os testes de aceitação são realizados por um grupo restrito de usuários finais do sistema, que simulam operações de rotina do sistema de modo a verificar se seu comportamento está de acordo com o solicitado. Teste formal conduzido para determinar se um sistema satisfaz ou não seus critérios de aceitação e para permitir ao cliente determinar se aceita ou não o sistema. Validação de um software pelo comprador, pelo usuário ou por terceira parte, com o uso de dados ou cenários especificados ou reais. Pode incluir testes funcionais, de configuração, de recuperação de falhas, de segurança e de desempenho.Teste de operaçãoNessa fase o teste é conduzido pelos administradores do ambiente final em que o sistema ou software entrará em ambiente produtivo. Vale ressaltar que essa fase é aplicável somente a sistemas de informação próprios de uma organização, cujo acesso pode ser feito interna ou externamente a essa organização. Nessa fase de teste devem ser feitas simulações para garantir que a entrada em produção do sistema será bem sucedida. Envolve testes de instalação, simulações com cópia de segurança dos bancos de dados, etc.. Em alguns casos um sistema entrará em produção para substituir outro e é necessário garantir que o novo sistema continuará garantindo o suporte ao negócio.(Fonte: http://pt.wikipedia.org/wiki/Teste_de_software)
Objeto / instância de uma classe. Um objeto é capaz de armazenar estados através de seus atributos e reagir a mensagens enviadas a ele, assim como se relacionar e enviar mensagens a outros objetos. Exemplo de objetos da classe Humanos: João, José, MariaMockobjects ou somente Mock em desenvolvimento de software são objetos que simulam o comportamento de objetos reais de forma controlada. São normalmente criados para testar o comportamento de outros objetos.Stubs = Com stubs, nos preocupamos em testar o estado dos objetos após a execução do método. Neste caso incluímos os asserts para ver se o método nos levou ao estado que esperamos.Mocks = Com mocks, a preocupação é testar a interação entre objetos durante a execução do método. Neste caso, os asserts servem para ver se os métodos se relacionaram como o esperado.Ferramentas: JAVA = EasyMock, JMock, MockCreator MockLib.NET = Moq, NMockLib, RhinoMocks, NMockandNMock 2 TypeMockRuby = Mocha, RSpec, FlexMockPHP = SimpleTest Yay! Mock SnapTest PHPUnit(Fonte: http://martinfowler.com/articles/mocksArentStubs.html)
Objeto / instância de uma classe. Um objeto é capaz de armazenar estados através de seus atributos e reagir a mensagens enviadas a ele, assim como se relacionar e enviar mensagens a outros objetos. Exemplo de objetos da classe Humanos: João, José, MariaMockobjects ou somente Mock em desenvolvimento de software são objetos que simulam o comportamento de objetos reais de forma controlada. São normalmente criados para testar o comportamento de outros objetos.Stubs = Com stubs, nos preocupamos em testar o estado dos objetos após a execução do método. Neste caso incluímos os asserts para ver se o método nos levou ao estado que esperamos.Mocks = Com mocks, a preocupação é testar a interação entre objetos durante a execução do método. Neste caso, os asserts servem para ver se os métodos se relacionaram como o esperado.Ferramentas: JAVA = EasyMock, JMock, MockCreator MockLib.NET = Moq, NMockLib, RhinoMocks, NMockandNMock 2 TypeMockRuby = Mocha, RSpec, FlexMockPHP = SimpleTest Yay! Mock SnapTest PHPUnit(Fonte: http://martinfowler.com/articles/mocksArentStubs.html)
Escrevemos o código primeiroNo desenvolvimento tradicional criarmos nossas interfaces, classes, métodos... Etc. E somente depois de termos algumas telas funcionando é que vamos testar. Desenvolvendo dessa maneira é muito comum percebermos que fizemos decisões equivocados no inicio do desenvolvimento. E quando percebemos isso em uma etapa já avançada do desenvolvimento, fica difícil e/ou muito custoso corrigir esses problemas e na maioria das vezes eles não são corrigidos, ou são corrigidos de formas paliativas.Código altamente acopladasMuitos desses problemas estão relacionados ao alto acoplamento no código. Classes dependendo de outras classes concretas ao invés de depender de interfaces, códigos duplicados, métodos ou até classes com muitas responsabilidades.Código difícil de entenderNecessidade de comentários para dizer o que o código fazOs códigos devem ser entendidos de maneira rápida pelos programados sem a necessidade de comentários.“Qualquer um consegue escrever código que um computador entenda. Bons programadores escrevem código que humanos possam entender” (Martin Fowler)Necessidade de alguém para explicar o que o código fazE quando nem os comentários existem? É preciso chamar o cara que desenvolveu pra explicar o que ele fez. E se esse cara não está mais na equipe? E se ele saiu da empresa?DebugNecessidade de fazer debug constantemente para saber se uma alteração no código está funcionando. Fazer debug só para saber se aquele novo IF se está funcionando é muito custoso e inviável. Até você navegar dentro sistema até chegar na tela que você precisa fazer o teste... Veja quanto tempo... É demorado. Não vale a pena.
Código mais claroO ciclo do TDD “força” os programadores a pensarem simples. Fazer o mais simples possível para um teste passar. Desse forma evita-se o uso desnecessário de patterns e/ou soluções mirabolantes e complexas. Em prol de fazer um código simples e que funcione.De novo: “Qualquer um consegue escrever código que um computador entenda. Bons programadores escrevem código que humanos possam entender” (Martin Fowler)Os testes podem ser usados como “documentação executável” Cada teste representa uma funcionalidade do sistema Toda vez que vamos acrescentar ou alterar uma funcionalidade no sistema, criamos um teste ou um conjunto de testes de unidade para ela. Esse conjunto de teste, serve como uma “documentação executável”, se amanhã um novo desenvolvedor entrar na equipe e precisar fazer uma manutenção em um sistema, podemos pedir que ele leia e execute os testes, isso já mostrará a ele quais as funcionalidades desse sistema. Claro que essa não deve ser a única documentação de um software. Mas desenvolvendo com TDD esse é um dos legados que ele nos proporciona.Feedback rápido sobre qualquer alteração no sistema.Outro legado que o TDD nos proporciona é a cobertura do código por testes de unidade. Essa cobertura permite que o programador tenha mais confiança em fazer alterações no código, por que a cada alteração, ele pode executar os testes de unidade e saber quase que instantaneamente se ele quebrou alguma parte do sistema, e se quebrou, qual a funcionalidade que deixou de funcionar e o porque. Isso permite que o programador faça mais alterações no sistema, em um tempo relativamente menor. Devido a confiança e a rapidez de feedback sobre o que ele está fazendo ser bem mais rápida e precisa do que debugando o sistema todo.Diminuição de DebugComo já mencionado, no desenvolvimento com TDD não precisamos executar e debugar o sistema para cada alteração do código para saber se uma nova funcionalidade está funcionando. Temos essa resposta de maneira quase instantânea apenas executando os testes de unidade.
Cobertura de Teste. (Funcionalidades)Se você seguir as regras do TDD, então praticamente 100% das linhas de código de produção em seu programa estarão cobertos por testes de unidade. Isto não cobre 100% dos caminhos no código, mas certifica que praticamente todas as linhas são executadas e testadas.Documentação.Os testes descrever o seu entendimento de como o código deve se comportar. Eles também descrevem a API. Por isso, os testes são uma forma de documentação. Os testes de unidade são normalmente muito simples e, portanto, são fáceis de entender. Além disso, são inequívocos e executáveis. Finalmente, se os testes forem executados todas às vezes que qualquer alteração no código for feita, eles nunca ficarão obsoletos.ArquiteturaQuando você escreve os testes primeiro, você se coloca na posição de um usuário da API de seu programa. Isso só pode lhe ajudar a executar um melhor design da API. Sua primeira preocupação, ao escrever os testes, é tornar mais fácil e conveniente o uso dessa API.Um módulo que é independentemente testável é um módulo que está desacoplado do resto do sistema. Quando você escrever os testes primeiro, você automaticamente desacopla os módulos que você está testando. Isso tem um profundo efeito positivo na qualidade geral do design do sistema.(Fonte: http://epf.eclipse.org/wikis/xppt/xp/guidances/guidelines/test_driven_development_tdd_D7F1F440.html#Benefits)A pequena granularidade do ciclo test-then-code dá um feedback contínuo ao programador. Falhas são identificadas mais rapidamente, enquanto o novo código é adicionado ao sistema. Assim, o tempo de depuração diminui compensado pelo tempo de escrita e execução dos casos de teste. Alguns estudos indicam que cerca de 50% das tarefas no processo de manutenção de software são envolvidas no processo de entendimento do código [Corbi1989]. A abordagem TDD ajuda na compreensão do programa porque os casos de teste e próprio código explicam melhor o funcionamento do sistema. Entretanto, esta prática permite somente o entendimento de uma parte do software. Para a compreensão da sua totalidade, é necessário que se faça uso de várias abstrações. (Fonte: http://www.inf.ufrgs.br/~cesantin/TDD-Eduardo.pdf)(Fonte: http://wiki.sintectus.com/bin/view/GrupoJava/VantagensDoTDD)Guidelines para TDD em JAVAhttp://epf.eclipse.org/wikis/xppt/xp/guidances/guidelines/test_driven_development_tdd_D7F1F440.html
É mais demorado desenvolver com TDDEu não sei o que testar / Testar é difícilDesenvolvendo com TDD eu não preciso de testes tradicionaisDiferença entre qualidade interna e externaO projeto está atrasado / eu não tenho tempo para fazer testesUm projeto atrasa um dia de cada vez. A cada dia que você negligencia uma boa prática em pról do Go Horse, é um dia que seu projeto atrasa. (Juan Lopes, DotNETArchitects)TDD só funciona com metodologias ágeis