Engenharia de Software | Gerenciamento de Projetos de Software | Test Driven Development – TDD e SCRUM
Por que estudar o TDD?
Os testes automatizados tem 2 funções importantes:
- Permitir refatoração
Podemos refatorar o código com mais segurança. Isto é, podemos alterar o código e verificar automaticamente se o software continua funcionando.
- Documentar
Os testes devem ter nomes que explicam quais funcionalidades eles testam, assim, ao executar o código, o desenvolvedor sabe quais funcionalidades foram implementadas e qual o comportamento esperado pelo código.
Como realizar o TDD?
A filosofia do TDD é que os testes guiem o próprio design das classes do sistema.
O processo TDD funciona da seguinte maneira:
1 – Faz-se o teste automatizado para o caso mais simples.
2 – Roda-se o teste (que não deverá passar, pois a funcionalidade ainda não foi implementada).
3 – Implementa-se através da mudança mais simples possível que faça o teste passar.
4 – Se o código não estiver o melhor possível:
- Refatora;
- Certifique-se de que os testes continuem passando.
5 – Se o código estiver bom – Volte para o primeiro item com o próximo teste mais simples.
Vejamos como os conceitos do TDD podem ser aplicados utilizando um exemplo para desenvolvimento de um simulador do jogo de cartas Black Jack.
Black Jack – teste 1
O Black Jack é jogado com um ou mais baralhos de 52 cartas, para cujos valores será designado um total de pontos.
As cartas de 2 a 10 terão o valor dos números. Reis, damas e valetes valem 10 pontos cada e ases poderão ser usados tanto como 1 ou 11. O objetivo para o jogador será comprar cartas até um total de 21 pontos (sem exceder), vencendo o total das cartas do distribuidor.
Defeito identificado!
Não existe Coringa no Black Jack.
public class Deck { private readonly Ilist<Card> cards = new List<Card>( ); public Deck( ){ cards.Add(Card.Dois_de_Copas); cards.Add(Card.Tres_de_Copas); //..restante de copas cards.Add(Card.Dois_de_Ouros); cards.Add(Card.Tres_de_Ouros); //..restante de ouros cards.Add(Card.Dois_de_Espadas); cards.Add(Card.Tres_de_Espadas); //..restante de Espadas cards.Add(Card.Dois_de_Paus); cards.Add(Card.Tres_de_Paus); //..restante de paus //Coringa cards.Add(Card.Coringa); }
Como testar automaticamente, em cada novo incremento, para que problemas assim não ocorram?
Serão testados automaticamente:
- 52 cartas no baralho.
- 13 Cartas de cada naipe.
- Não pode existir carta coringa.
- Uma carta de cada tipo.
Teste 1: Existem 52 cartas no baralho?
public class DeckTest{ public void Verify_Deck_contains_52_cards( ) { var deck = new Deck( ); Assert.AreEqual(52,deck.Count( ) ); } }
Black Jack – teste 2
Teste 2: Existem 13 cartas de cada naipe?
Classe que testa se existem 52 cartas no baralho e se são 13 de cada naipe.
public class DeckTest2{ public void Verify_Deck_contains_52_cards( ){ var deck = new Deck( ); Assert.AreEqual(52,deck.Count( ) ); } public void Verify_Deck_contains_13_cards_for_each_suit( ) { var deck = new Deck( ); Assert.AreEqual(13,deck.NumberofCopas( ) ); Assert.AreEqual(13,deck.NumberofEspadas( ) ); Assert.AreEqual(13,deck.NumberofOuros( ) ); Assert.AreEqual(13,deck.NumberofPaus( ) ); } }
Black Jack – teste 3
Teste 3: Há carta Coringa?
public class DeckTest2{ //..Continuação public void Verify_Deck_contains_no_joker( ) { var deck = new Deck( ); Assert.IsFalse(deck.Contains(Card.Coringa ) ); } }
Classe que testa se há coringa nas cartas geradas.
Black Jack – teste 4
Teste 4: Existe apenas uma carta de cada tipo?
public class DeckTest2 { //..Continuação public void Verify_Every_Card_in_the_Deck ( ){ var deck = new Deck( ); Assert.IsTrue(deck.Contains(Card. Dois_de_Copas ) ); Assert.IsTrue(deck.Contains(Card. Tres_de_Copas ) ); //...Testar todas as cartas válidas para cada naipe } }
Classe que testa se existe apenas uma carta de cada tipo.
Classes para Testes
- 52 cartas no Baralho — testado.
- 13 Cartas de Cada Naipe — testado.
- Não pode existir carta Coringa — testado.
- Uma carta de Cada Tipo — testado.
Este pequeno exemplo ilustra como gerar classes em função dos testes necessários.
Uma vez implementado, qualquer novo incremento no código irá passar por estes testes, já que eles fazem parte do código.
SCRUM
Scrum é um método ágil empírico, iterativo com entregas incrementais.
Empírico porque apoia-se no empirismo que afirma que o conhecimento vem da experiência e de tomada de decisões baseadas no que é conhecido. O Scrum emprega uma abordagem iterativa e incremental para aperfeiçoar a previsibilidade e o controle de riscos
História
Scrum é baseado em um artigo de 1986 escrito por Hirotaka Takeuchi e Ikujiro Nonaka para a Harvard Business Review, o “The Game Development New New Product”.
Fonte: <http://training-course-material.com>. Acesso em: 26 abr. 2015.
Neste trabalho, os autores utilizaram o esporte do rugby como uma metáfora para descrever os benefícios da auto-organização de equipes de desenvolvimento de produtos inovadores e de entrega.
Jeff Sutherland, Ken Schwaber e Mike Beedle aderiram às ideias deste artigo, incluindo a metáfora, e aplicou-as na área de desenvolvimento de software. Eles chamaram seu novo método de Scrum.
Schwaber e Beedle escreveram sobre suas experiências em seu livro Desenvolvimento de Software Ágil com Scrum em 2002.
Pilares SCRUM
Como o Scrum é baseado no empirismo, os seus pilares baseiam-se em:
Transparência
Todo o processo deve estar visível a todos os envolvidos. Essa transparência deve ser refletida no ambiente, nas pessoas e nos processos.
Inspeção
O processo em si deve ser inspecionado regularmente na busca por anomalias e/ou oportunidades de melhorias.
Adaptação
Caso a inspeção detecte algum processo que precise ser ajustado ou melhorado, as adaptações deverão ser feitas o mais rápido possível. O quanto antes as mudanças forem feitas, o novo processo proposto é testado e validado.
No Scrum temos oportunidades constantes de verificar os 3 pilares (Transparência, Inspeção e Adaptação), e essas oportunidades estão nos eventos da Reunião de Planejamento, Scrum Diário, Reunião de Revisão do Sprint e Reunião de Retrospectiva do Sprint.
O framework SCRUM
Scrum é um framework (incompleto) para suportar o desenvolvimento e manutenção de projetos/produtos complexos. É incompleto, pois, na verdade, ele simplesmente fornece uma estrutura para entrega, mas não diz como fazer práticas específicas, deixando isso para a equipe determinar.
O projeto começa com uma visão clara oferecida pelo negócio, e um conjunto de características do produto em ordem de importância. Esses recursos fazem parte da carteira de produtos, que é mantida pelo cliente ou representante do cliente referido como o Product Owner. Uma caixa de tempo comumente referida como uma iteração ou Sprint é a quantidade de tempo que a equipe tem para concluir as características selecionadas.
Sprints têm geralmente de uma a quatro semanas de duração, e essa duração é mantida durante toda a vida do projeto. O Product Owner (negociando com o time) seleciona itens do Product Backlog que acredita que pode ser concluída no Sprint, e cria um Sprint backlog composto pelos recursos e tarefas, como parte da reunião de planejamento (planning meeting) do Sprint.
Dica 1
O tamanho do Sprint é influenciado (ou pode ser alterado) dependendo do escopo, tamanho do time, disponibilidade do cliente, conhecimento do time sobre agilidade, conhecimento do time sobre a tecnologia, mudanças na formação do time. Porém, sempre que um novo tamanho é definido, as métricas de produtividade deverão ser refeitas.
Uma vez que o time se comprometeu com um Sprint backlog, o trabalho começa. Durante este tempo, no Sprint, a equipe está protegida de interrupções e permitiu concentrar-se em atender o objetivo do Sprint. Nenhuma alteração para o Sprint backlog são permitidas, no entanto, o product backlog pode ser alterado, em preparação para o próximo Sprint.
Dica 2
A regra do scrum não permite que o Sprint Backlog seja alterada, porém, se o item que está em desenvolvimento perde o objetivo de negócio, isto é, não agrega mais valor, não faz sentido continuar a ser desenvolvido, e deve ser interrompido. Geralmente o tempo restante do Sprint pode ser dedicado à refatoração de códigos existentes ou pode se iniciar um novo Sprint, mas são casos de exceção.
Durante o Sprint a equipe verifica no diário com o outro sob a forma de uma reunião, geralmente de 10 a 15 minutos conhecido como Daily Scrum (Scrum Diário).
No final do Sprint o time (e o cliente, quando possível) reúnem-se para a reunião conhecida como revisão (review). Eles também possuem uma reunião de retrospectiva (retrospective) com o objetivo de aprender como melhorar. Essa reunião é fundamental, pois seu foco é sobre os três pilares do Scrum: transparência, inspeção e adaptação.
Referências
RIBEIRO, Rafael Dias; CUNHA, Horácio da; RIBEIRO, Sousa. Gerenciamento de Projetos com Métodos Ágeis. Rio de Janeiro: [s.n.], 2015. ISBN:9788591910212. Disponível em: http://www.saraiva.com.br/gerenciamento-de-projetos-com-metodos-ageis-8890292.html
outros: http://www.extremeprogramming.org/
Engenharia de Software | Gerenciamento de Projetos de Software | Test Driven Development – TDD e SCRUM