Este documento discute técnicas para escrever testes unitários para código legado, como testes de caracterização para documentar o comportamento atual e uso de isolamento através de mocks para evitar dependências. Também aborda como alcançar cobertura total de código, testar casos especiais e validações, e escrever testes para reproduzir bugs.
3. Banco
de Dados +
Objeto
Relacional
Teste
automatizado
Orientação
a Objetos
Ambientes de
Desenvolvimento
Servidores
de Aplicação
+ REST
+ SOAP
Distribuição
+ Nuvem
Bibliotecas +
Frameworks
Refactoring +
Análise EstáticaProfiling
Comunidade++
2015:
20 anos
Integração
Contínua Programação
Funcional +
Scala
4. Em várias empresas perto de você:
"O Gigantesco Projeto
Escrito em Java"
10+ anos em produção
milhares de classes
milhões de linhas
de código desktop / web / mobile
centenas de jars, wars, ears
dúzias de frameworks
… e crescendo!
9. Manual Prático
de Paraquedismo
"In the industry, legacy code
is slang for difficult-to-change
code that we don't understand.
!
To me, legacy code
is simply code without tests."
!
- Michael C. Feathers
16. Alternativa 1
1. Estudar a documentação do framework
2. Instalar / importar / emprestar uma base de dados
3. Popular a base com os dados de teste
4. Logar na base
5. Rodar o teste
23. new MassMailingService().send(
new Message("Hello"),
"andre.oliveira@liferay.com",
"andre@arbo.com.br");
30 segundos depois…
Você possui 1 (uma) nova
mensagem
em
sua caixa postal
Você possui 1 (um
a) nova
m
ensagem
em
sua caixa postal
29. Isolamento e legado
Código novo,
testes novos?
Use o bom senso, ou…
"TDD is dead. Long live testing"
http://david.heinemeierhansson.com/2014/tdd-is-dead-long-live-testing.html
!
"Is TDD dead?"
http://martinfowler.com/articles/is-tdd-dead/
31. if (service.result() > 5) { /* caso especial */ }
@Test public void happyDay() {
when(service.result()).thenReturn(1);
// do it + assert happy day
}
!
@Test public void casoEspecial() {
when(service.result()).thenReturn(42);
// do it + assert caso especial
}
Condicionais e casos especiais
Cada if branch deriva um caso de teste
32. try { service.danger(); }
catch (OpaException e) { /* caso especial */ }
!
@Test public void sorryDay() {
when(service.danger())
.thenThrow(OpaException.class);
// do it + assert caso especial
}
Tratamento de exceções
Cada catch branch deriva um caso de teste
33. if (pessoa.idade() < 0) {
throw new IdadeNegativaException();
}
!
@Expected(IdadeNegativaException.class)
@Test public void wtf() {
when(pessoa.idade()).thenReturn(-99);
// do it (vai lançar a exception)
}
Validações
Simulando entradas impossíveis com mocks
35. Bugfixes:
cobertura
mínima
• Rastrear a linha de código do bug
• Escrever teste para o fragmento de lógica
• Mock mínimo que reproduz o problema
• Protip: Extrair método testável
36. Testes unitários com
isolamento: benefícios
2
3
4
5
6
Rodam em < 1 segundo
(como integração
chegavam a 30+)
Dispensam preparar
base de dados ou
serviços
Fácil conseguir 100%
de cobertura
Blindagem contra
colaboradores mal
comportados
Simular exceptions,
casos especiais e dados
ruins
Modularização de
Projetos Java
Gigantescos
1