Você está na página 1de 62

Introdução ao

Desenvolvimento
Orientado a Testes
(Test-Driven Development -
TDD)
Fabrício Matos
Dez/2008
Introdução
 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;

2
Introdução
 Objetivo do TDD:
◦ “clean code that works”
◦ 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;

3
Principais Benefícios do
TDD
 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.

4
Organização da
Apresentação
 A Metodologia TDD
 Estudo de Caso: Aplicação do TDD na IBM
 Construção de Casos de Testes com NUnit
 Considerações Finais

5
A Metodologia TDD
Baseado principalmente em

Kent Beck
Test-Driven Development By Example,
2003

6
Tipos de Testes
 Testes de Unidade: Testa uma unidade mínima
do software;
 Testes de Integração: Testa a comunicação entre
os módulos;
 Testes de Sistema: Testa todo o sistema para
verificar se atende aos requisitos;
 Testes de Integração de Sistema: Testa a
comunicação do sistema com outros sistemas
com os quais interage;
 Testes de Aceitação: Testes realizados pelo
usuário final para verificar se o sistema faz o
que ele espera;

7
Tipos de Testes
 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)

8
A “Espiral da Morte” do
Teste
 O ciclo mortal do “estou sem tempo para
testar”:

9
Princípios
 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 “Test List”
◦ 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;

10
Princípios
 Mas o que testamos?
◦ Fluxos Condicionais (IFs, Switches, etc.)
◦ Polimorfismos
◦ Loops
◦ Operações
◦ Etc..

11
Princípios
◦ 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;

12
Princípios
◦ 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);

13
Princípios
 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;
◦ 14
Princípios
 Exemplo: Testar o envio da string
“Qualidata” através de um socket.
 public void TestarComunicacaoSocket()
public void
public voidTestarComunicacaoSocket()
TestarComunicacaoSocket()
{ { public void TestarComunicacaoSocket()
 { {
Socket readerSocket
= new=Server(8080,
new Socket(“localhost”,
Assert.IsTrue(readerSocket.Close());
Server server 8080);
“”Qualidata”);
string
stringbuf = reader.Contents();
buf readerSocket
= reader.Contents();
 Assert.AreEqual(“Qualidata”,
Socket =buf);
new Socket(“localhost”, 8080);
} string buf = reader.Contents();
Assert.IsTrue(readerSocket.Close());
Assert.IsTrue(readerSocket.Close());
 Assert.AreEqual(“Qualidata”,
Assert.AreEqual(“Qualidata”, buf);
buf);
} } Assert.IsTrue(readerSocket.Close());
Assert.AreEqual(“Qualidata”, buf);
 }


15
Princípios
 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

16
Princípios
 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:

[Test]
[Test]
public void Testar_Fatorial_8()
public void Testar_Fatorial_8()
{
{
Assert.AreEqual(40320, Matematica.Fatorial(8));
Assert.AreEqual(8 * 7 * 6 * 5 * 4 * 3 * 2, Matematica.Fatorial(8));
}
}

17
“Red Bar Patterns”
 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?

18
“Red Bar Patterns”
 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).

19
“Red Bar Patterns”
 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.

20
“Red Bar Patterns”
 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.


◦ 21
“Testing Patterns”
 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.
 Mock Objects
◦ 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 Rhino Mocks.

◦ 22
“Testing Patterns”
 Log String
◦ Como testar se uma sequência de métodos foi
chamada numa certa ordem?
◦ Guarde um log (trace log) de cada execução dos
métodos chamados em uma string e compare
com o valor esperado.
 Teste de Falhas
◦ Precisamos assumir que “código que não foi
testado não funciona”. Mas como testar falhas
que são difíceis de se reproduzir (disco cheio,
falha de comunicação, etc.)?
◦ “Fake it!”, ou seja, construa uma nova classe
que gere a exceção e simule a falha.


23
“Testing Patterns”
 Desenvolvendo Sozinho – Teste Quebrado
◦ Se você está desenvolvendo uma software sozinho, é
sempre melhor encerrar uma sessão de
programação deixando um teste vermelho
(incompleto).
◦ Isso agiliza a continuação do trabalho no próximo
dia.
 Desenvolvimento em Equipe – Testes Rodando
◦ Se você trabalha em equipe, não faça check-in de
testes vermelhos. Isso vai ser ruim pois todos vão
achar que há um requisito que foi “estragado”,
enquanto na verdade ele ainda não foi finalizado.
◦ Ao subir suas alterações (check-in), rode todos os
testes para garantir a integração entre os módulos.
◦ Se os testes não forem muito lentos, procure rodar
todos os testes em sua própria estação para
antecipar problemas de integração.

24
“Green Bar Patterns”
 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.

25
“Green Bar Patterns”
 “Fake it ‘til you make it” (simule até
construir realmente)
◦ Por exemplo, qual é a forma mais simples de
implementar o código abaixo?
◦ public void TestarSoma() {
Assert.AreEqual(5, Somar(2,3));
◦ }

◦ A forma mas direta seria:
 public void TestarSoma() {
Assert.AreEqual(5, Somar(2,3));
 }

 public int Somar(int x, int y) {


return 5;
 }


26
“Green Bar Patterns”
 Triangulação
◦ Quando você tem dois ou mais testes, você
precisa de uma implementação que atenda a
todos simultaneamente.
◦ public void TestarSoma()
{
◦ Assert.AreEqual(5, Somar(2,3));
Assert.AreEqual(7, Somar(3,4));
◦ }

◦ 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”.

27
“Testing Patterns”
 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.

28
“Testing Patterns”
 Operações Sobre Coleções
◦ Implemente primeiro o teste para a operação
recebendo um elemento;
◦ Depois estenda para a operação recebendo a
coleção;
 Testes de Exceções
◦ Como testar se em determinadas condições uma
exceção é gerada?
◦ Use try ... Teste ... Assert.IsTrue(false) ... catch ...
◦ Ou use algum recurso específico do seu framework
de testes (um “xUnit” da vida), se houver:
[ExpectedException(typeof(QException), "O atributo Pessoa.Nome não pode ser nulo.")]

public void TestarNomeNaoNulo()
{
Pessoa p = new Pessoa();
Conexao.Save(p);
}

29
“Refactoring”
 Refatorar é melhorar o “design” de funcionalidades do
sistema, sem alterar seu comportamento;
 Em TDD, devemos refatorar mantendo todos os testes
“verdes”;
 Em TDD, primeiro pensamos em resolver o problema da
 Por que refatorar o código?
◦ Para torná-lo mais legível;
◦ Para facilitar sua manutenção, seja na correção de bugs ou na
adição de novas funcionalidades, aumentado assim sua vida
útil;
◦ Para ajustar decisões de projeto estejam impactando
negativamente o sistema (limitando, deixando lento, etc..)
◦ Para buscar o “clean” de “clean code that works”
 Embora seja um assunto que possa ser trabalhado de
forma mais específica, trabalharemos alguns exemplos
de técnicas de refatoração de código.


30
“Refactoring”
 Reconcilie Diferenças
◦ Se duas partes do código poderem ser iguais,
então poderemos eliminar uma delas;
◦ Dois loops poderiam ser fundidos em um só;
◦ Se dois caminhos em um condicional forem
iguais, poderemos eliminar a condição;
◦ Se dois métodos foram iguais, podemos eliminar
um;
◦ Se duas classes forem iguais, podemos eliminar
uma;

31
“Refactoring”
 Isole as Alterações
◦ Se você precisa alterar uma parte específica de um
método divido em partes (seções), primeiro isole essa
parte (refatoração) e depois faça a alteração;
 Migrar Dados
◦ Como migrar dados de uma estrutura para outra? (Por
exemplo, de um DataSet para uma lista)
◦ Duplique os dados primeiro criando uma nova variável
(mantenha o DataSet e crie também a lista)
◦ Inicialize também a nova variável (lista) em todo lugar
que a antiga (DataSet) é inicializada;
◦ Substitua a implementação para que seja utilizada a
nova estrutura variável (lista) ao invés da antiga
(DataSet)
◦ Elimine a variável da estrutura original (o DataSet).
◦ Entre todos esses passos os testes não devem deixar
de permanecer verde.


32
“Refactoring”
 Extraia Métodos
◦ Simplifique métodos muito longos, criando
métodos menores (variáveis locais utilizadas
também fora do trecho devem virar
parâmetros)
◦ Não se deve ir tão longe ao ponto de criar tantas
indireções que acabem dificultando a leitura.
◦ Blocos de código com aquele típico comentário
no início são excelentes candidatos a novos
métodos. Exemplo:
//Verifica se o aluno atende a todos os pré-requisitos para ser matriculado
linha 1
linha 2
...
linha N

33
“Refactoring”
 Métodos “Inline”
◦ Esse é o ato de substituir uma chamada de um
método pelo seu conteúdo (o oposto da
técnica anterior)
◦ Isso é especialmente útil quando você está
tendo dificuldade de entender um código
confuso, cheio de indireções.
◦ Nesses casos pode ser melhor simplesmente
desfazer (via “inline”) algumas camadas de
abstração, entender o que o código faz, e
depois repensar a melhor forma de reorganizá-
lo.

34
“Refactoring”
 Mover Métodos
◦ Como mover métodos para outros “lugares” sem
exigir uma alteração imediata em todos as suas
chamadas?
◦ Crie o novo método no lugar que deseja;
◦ Mova o conteúdo do método;
◦ No método original, faça uma chamada ao novo
método, repassando os parâmetros.
 Adicionar Novo Parâmetro
◦ Pode ser visto como um caso de “Migrar Dados”
◦ Também pode ser utilizado o próprio compilador para
mostrar onde será necessário alterar sua chamada;

35
“Refactoring”
 Mover Parametros de Métodos para
Construtores
◦ Por que? Se você passa o mesmo parâmetro
para vários métodos de uma classe, pode ser
melhor passá-lo uma única vez em seu
constructor, e simplificar as chamadas dos
métodos;
◦ Como?
Adicione o parâmetro ao constructor;
Adicione uma nova variável de instância com o
mesmo nome do parâmetro, e inicialize ela no
constructor;
Um por um, converta todas as ocorrências de
“parametro” nos métodos por “this.parametro”.

36
“Refactoring”
 Mover Parametros de Métodos para
Construtores (...continuação)
Quando não houver mais referências a
“parametro”, elimine-o da assinatura do
método e de todas suas chamadas;
Remova o “this.” que agora é supérfluo;
Renomeie a variável de instância
apropriadamente.

37
Projeto OO (OOD) e
Arquitetura “Tipo-Classe”


38
Projeto OO (OOD) e
Arquitetura “Tipo-Classe”
 Exemplo - “Sistema Acadêmico”
 Caso de Uso “135 - Enturmar Alunos em Lote”
◦ Curso Normal:
(1) Usuário seleciona o ano/período letivo em questão;
(2) Usuário seleciona uma turma desse ano/período
letivo;
(3) Usuário solicita ao sistema a lista dos alunos
candidatos e serem enturmados conforme RN-056;
(4) Usuário seleciona os alunos que serão enturmados
(deve existir a opção “selecionar todos”);
(5) Usuário clica no botão “Enturmar”;
(6) Sistema executa o caso de uso “047 - Enturmar
Aluno” para cada aluno selecionado;
(7) Sistema exibe uma mensagem com um tipo de “log
de execução” indicando o resultado da enturmação
de cada aluno.

39
Projeto OO (OOD) e
Arquitetura “Tipo-Classe”
 Exemplo - “Sistema Acadêmico”
◦ RN-056: Para os cursos seriados, o
procedimento de enturmar alunos deve
permitir a listagem (com filtros opcionais por
matrícula e nome) de alunos ativos, do mesmo
curso e série que a turma selecionada,
matriculados no ano/período letivo da turma, e
que ainda não estejam enturmados.

40
Projeto OO (OOD) e
Arquitetura “Tipo-Classe”
 Exemplo - “Sistema Acadêmico”
 Decisões de Projeto:
◦ Quem assumirá a responsabilidade de listar os
“alunos enturmáveis” conforme a RN-056?
1. A própria página/janela, através de uma consulta
(LINQ, p.e.)?
2. Uma classe de controle (gerência de tarefas), através
de uma consulta (LINQ, p.e.)?
3. Um método estático Aluno.Listar( ... ) que receba uma
lista genérica de opções de filtro, de modo que na
chamada específica desse caso de uso os filtros
garantam a RN-056?
4. Um método de instância bem específico como:
turmaX.ListarAlunosEnturmaveis()?
5.
6.
7.
 41
Projeto OO (OOD) e
Arquitetura “Tipo-Classe”
 Exemplo - “Sistema Acadêmico”
 Decisões de Projeto:
◦ Como implementar o método
turmaX.ListarAlunosEnturmaveis()?
1. Fazendo uma consulta sobre toda a base de
dados completa (utilizando XPQuery, por
exemplo)?
2. Fazendo um consulta sobre os objetos
relacionados à turmaX!
3.
4.
5.


42
“Mastering TDD”
 Qual o tamanho ideal dos passos “vermelho-
verde-refatorar”?
Você pode escrever testes que vão te levar a
escrever uma única linha de código;
Também pode escrever testes que vão te levar à
escrever centenas de linha de código;
Não há uma regra, mas a tendência dos
experientes em TDD é clara: Passos pequenos.

43
“Mastering TDD”
 Características de um bom teste
◦ Se você tem dificuldade para identificar um
lugar comum para inicializações
compartilhadas, então você deve ter um
problema de projeto – muitos objetos
entrelaçados.
 Quanto feedback (asserts) você precisa?
◦ Depende. Por exemplo, pode ser muito
improvável um problema de diskfull, e você
está confiante que esse é um teste
desnecessário no cenário do software em
questão.

 44
“Mastering TDD”
 Quando excluir um teste?
◦ Quanto mais testes, melhor;
◦ Se dois testes fazem a mesma coisa, pode ser, mas
considere:
Na dúvida, não exclua;
Se os dois testes seguem o mesmo fluxo de execução,
mas comunicam (documentam) questões diferentes,
deixe-os assim.
 TDD é Escalável?
◦ O maior sistema totalmente TDD que o autor
participou foi na LifeWare:
40 pessoas, por 4 anos
250KLOC de código funcional
250KLOC de código de teste
4000 testes que levam 20min para executar

 45
“Mastering TDD”
 Como iniciar TDD em um sistema desenvolvido
sem Testes Automatizados?
◦ Muitos livros ainda precisam ser escritos sobre isso;
◦ Um primeiro problema é que código que não foi
escrito pensando nos testes é difícil de ser testado;
◦ Outro problema é que alterações nesse código são
perigosas pois não temos os testes para garantir
que tudo continua funcionando;
◦ O ideal seria primeiramente implementar testes
automáticos para todo o sistema e depois partir
para desenvolver as novas funcionalidades com
TDD;
◦ Outra opção é explorar outras formas de feedback,
como testes de nível de aplicação, que garanta
certo nível de confiança.

 46
Organização da
Apresentação
 A Metodologia TDD
 Estudo de Caso: Aplicação do TDD na IBM
 Construção de Casos de Testes com NUnit
 Considerações Finais

47
TDD na IBM
 Baseado no artigo:
 [1]E. M. Maximilien and L. Williams, "Assessing test-
driven development at IBM", Proceedings of the 25th
International Conference on Software Engineering pp. 564-
569, Portland, Oregon, USA, IEEE Computer Society, 2003.

 O sistema: JavaPOS (www.javapos.com)


◦ Um conjunto de serviços (JavaBeans) para
permitir o acesso a dispositivos POS (point of
sale), tais como impressoras, caixas (dinheiro),
leitores magnéticos, etc..
◦ Implementado através de uma parceria da IBM,
NCR, Epson e Sun.

48
TDD na IBM
 Motivação
◦ Implementação do JavaPOS original (sem TDD)
contava com uma equipe que conehcia muito
bem suas especificações e tinha grande
experiência com dispositivos POS;
◦ Em cada fase de FVT (Functional Verification
Test), executada antes de cada novo release, a
taxa de defeitos não diminuía como esperado.
◦ Por isso desenvolvedores e gerentes estavam
abertos a novas abordagens.

49
TDD na IBM
 Experiência Anterior com Testes
◦ Criavam algumas classes de teste de forma ad-
hoc para partes mais importantes do código;
◦ O processo de construção de testes não era
sistemático, sendo uma atividade pós-
desenvolvimento;
◦ Na maioria das vezes, nenhum teste era criado.
Especialmente quando os cronogramas
estavam apertados, os desenvolvedores
precisavam parar para resolver problemas de
desenvolvimentos anteriores, ou ainda os
novos requisitos não estavam muito claros


50
TDD na IBM
 Experiência Anterior com Testes (cont.)
◦ A maioria dos testes de unidade eram
desperdiçados;
◦ Eles não eram executados na fase de verificação
funcional (FVT)
◦ Também não eram aproveitados em versões
posteriores (novos releases) do software;
◦ Não tinham qualquer experiência com TDD.

51
TDD na IBM
 Adoção da Metodologia TDD - No início havia
muitas dúvidas:
◦ Taxa de Defeitos – Como TDD vai afetar a taxa de
defeitos a curto prazo (próximo release) e a longo
prazo (futuros releases)?
◦ Produtividade - Qual será o impacto? Trabalhavam
com uma média de 400LOC / pessoa-mês.
◦ Frequência dos Testes – Qual será o percentual de
testes automatizados em relação a testes
iterativos? Quão frequentemente cada tipo de teste
será executado?
◦ Projeto – Como TDD vai afetar a qualidade do projeto
(design)? Eles avaliam isso através da capacidade
de lidar com requisitos identificados tardiamente,
ou a inclusão de novos dispositivos ou serviços.
◦ Integração – TDD e seus testes de regressão
automatizados irão suavizar os processos de
integração?

52
TDD na IBM
 O Trabalho com TDD
◦ No início muitos desenvolvedores e gerentes
estavam preocupados pois uma metodologia
tão rigorosa poderia afetar a produtividade a
ponto de inviabilizar a manutenção dos
cronogramas existentes.
◦ Apesar das metodologias ágeis sugerirem
nenhum projeto a priori, no javaPOS os
requisitos eram bem estáveis, e a equipe
optou por desenvolver diagramas de classes e
de sequência;
◦ Acrescentaram nas atividades de projeto, além
dos diagramas UML, a criação de casos de
teste (teste de sistema);

53
TDD na IBM
 O Trabalho com TDD
◦ Para cada classe pública A, tinham uma classe
TesteA, e para cada método de A, métodos de
teste correspondentes em TesteA.
◦ Havia casos em que era necessário tratar
cenários diferentes do mesmo caso de teste.
Por exemplo, impressoras que trabalhavam de
modo síncrono ou assíncrono, exigiam casos
de teste específicos para cada cenário;
◦ Definiram como meta um mínimo de 80% de
cobertura de teste automatizado (o restante
poderia ser testes iterativos);

54
TDD na IBM
 O Trabalho com TDD
◦ Cada documento de especificação de projeto
continha uma secção de testes descrevendo
todas as classes e métodos importantes que
deveriam ser testados;
◦ Diariamente todo código era compilado
automaticamente, e todos os testes
executados.
Para cada build, um email era enviado para cada
membro da equipe com a lista de testes
executados e eventuais erros encontrados.
Em um primeiro momento, esses builds eram
gerados várias vezes por dia;

55
TDD na IBM

56
TDD na IBM
 Resultados
◦ Números do Projeto:
71.4 KLOC de código de negócio e 34 KLOC de
código Junit;
Densidade de erros, que normalmente é de 8
erros/KLOC foi de 4 erros/KLOC (50% de
redução)
OBS: Atualmente, devido ao TDD, nossa
densidade média de erros é de 3.7 erros/KLOC.
Foram escritos 2390 casos de teste JUnit. Outros
100 testes foram escritos para avaliar
performance;

57
TDD na IBM
 Resultados
◦ Taxa de Defeitos – Com TDD, os testes automatizados
realmente foram feitos. Como resultado obtiveram um
excelente redução de 50% de defeitos na fase de
verificação funcional (FVT)
◦ Produtividade – Não só manteve-se dentro dos cronogramas,
como obtiveram uma pequena melhoria em relação à média
de 400LOC/pessoa-mês;
◦ Frequência dos Testes – Escreveram aproximadamente 2500
testes automáticos e 400 testes iterativos, ou seja, 86% de
cobertura de teste automático, acima da meta de 80%.
◦ Projeto – Acreditam que TDD ajudou a produzir um sistema
que recebe mais facilmente mudanças. Inclusive alguns
dispositivos foram incluídos no projeto quando o mesmo já
tinha avançado mais de 2/3 do cronograma.
◦ Integração – Antes integravam somente próxima à fase de
FVT. Com TDD e integrações (builds) diários, diminuíram
muito os riscos pois problemas aparecem bem mais cedo.

58
TDD na IBM
 Lições aprendidas sobre a transição para
TDD:
◦ Comece TDD no início do projeto;
◦ Ajuste as expectativas da equipe pois no início
TDD parece menos produtivo e frustrante pelo
tempo que se leva para criar os testes; Na
prática, no final das contas, não haverá
impacto negativo na produtividade.
◦ Para uma equipe nova em TDD, inicie builds
diários mais adiante um pouco. Não muito
cedo nem muito tarde (após 1/3 do
cronograma, por exemplo). Enquanto isso cada
um deve executar os seus testes em sua
estação.

◦ 59
TDD na IBM
 Lições aprendidas sobre a transição para TDD:
◦ Convença a equipe de adicionar novos casos de tese
sempre que um problema for encontrado, não
importando onde seja. Isso vai garantir a solução
do problema em algum momento à frente;
◦ Definimos 80% de cobertura como um objetivo
mínimo. É extremamente importante os builds
diários automáticos. Eles se tornam a batida que dá
o ritmo ao projeto e ao mesmo tempo facilita
acompanharmos seu progresso;
◦ Encorage a construção de testes que executem
rapidamente e de projeto eficiente;
◦ Aproveite sempre para encorajar a equipe a escrever
mais testes, por exemplo, monitorando qual
subsistema tem mais testes implementados.



60
Organização da
Apresentação
 A Metodologia TDD
 Estudo de Caso: Aplicação do TDD na IBM
 Construção de Casos de Testes com NUnit
 Considerações Finais

61
Organização da
Apresentação
 A Metodologia TDD
 Estudo de Caso: Aplicação do TDD na IBM
 Construção de Casos de Testes com NUnit
 Considerações Finais

62

Você também pode gostar