SlideShare uma empresa Scribd logo
1 de 43
Como escrever bons testes! 
por Danilo De Luca e Dherik Barison
“Trying to improve software quality by increasing the 
amount of testing is like trying to lose weight by 
weighing yourself more often” 
Steve McConnell - Code Complete
Motivação 
• Importância 
• Pouca conversa aprofundada sobre o tema 
• Será que realmente sabemos o fazer um teste 
ser bom... 
• Falta de visibilidade de que o código de um 
teste deve ser tão bom quanto um código de 
“business”
O que faz um teste ser bom? 
• Performance 
• Manutenabilidade 
• Clareza 
• Resiliência 
• Precisão
Como escrever um teste bom? 
• Testes devem servir como uma documentação do sistema 
• Os nomes dos testes devem dizer o que eles fazem 
• Não deve conhecer detalhes de implementação* 
• Não deve exibir informações que distraiam do objetivo do 
teste 
• Um novo comportamento na aplicação não deve alterar os 
testes antigos, apenas adicionar novos testes
Como conseguir um teste bom? 
Ruim: 
@Test 
public void shouldPerformAddition() { 
Calculator calculator = new Calculator(new RoundingStrategy(), 
"unused", ENABLE_COSIN_FEATURE, 0.01, calculusEngine, false); 
int result = calculator.doComputation(makeTestComputation()); 
assertEquals(5, result); // De onde este número veio? 
}
Como conseguir um teste bom? 
Ruim: 
@Test 
public void shouldPerformAddition() { 
Calculator calculator = new Calculator(new RoundingStrategy(), 
"unused", ENABLE_COSIN_FEATURE, 0.01, calculusEngine, false); 
int result = calculator.doComputation(makeTestComputation()); 
assertEquals(5, result); // De onde este número veio? 
}
Como conseguir um teste bom? 
Ruim: 
@Test 
public void shouldPerformAddition() { 
Calculator calculator = new Calculator(new RoundingStrategy(), 
"unused", ENABLE_COSIN_FEATURE, 0.01, calculusEngine, false); 
int result = calculator.doComputation(makeTestComputation()); 
assertEquals(5, result); // De onde este número veio? 
}
Como conseguir um teste bom? 
Bom: 
@Test 
public void shouldPerformAddition() { 
Calculator calculator = newCalculator(); 
int result = calculator.doComputation(makeAdditionComputation(2,3)); 
assertEquals(5, result); 
}
Como conseguir um teste bom? 
Bom: 
@Test 
public void shouldPerformAddition() { 
Calculator calculator = newCalculator(); 
int result = calculator.doComputation(makeAdditionComputation(2, 3)); 
assertEquals(5, result); 
}
Como conseguir um teste bom? 
Bom: 
@Test 
public void shouldPerformAddition() { 
Calculator calculator = newCalculator(); 
int result = calculator.doComputation(makeAdditionComputation(2, 3)); 
assertEquals(5, result); 
}
Como conseguir um teste bom? 
Ruim: 
@Test 
public void isUserLockedOut_invalidLogin() { 
authenticator.authenticate(username, invalidPassword); 
assertFalse(authenticator.isUserLockedOut(username)); 
authenticator.authenticate(username, invalidPassword); 
assertFalse(authenticator.isUserLockedOut(username)); 
authenticator.authenticate(username, invalidPassword); 
assertTrue(authenticator.isUserLockedOut(username)); 
}
Como conseguir um teste bom? 
Bom: 
@Test 
public void isUserLockedOut_lockOutUserAfterThreeInvalidLoginAttempts() { 
authenticator.authenticate(username, invalidPassword); 
assertFalse(authenticator.isUserLockedOut(username)); 
authenticator.authenticate(username, invalidPassword); 
assertFalse(authenticator.isUserLockedOut(username)); 
authenticator.authenticate(username, invalidPassword); 
assertTrue(authenticator.isUserLockedOut(username)); 
}
Quais as dificuldades mais comuns? 
• Preparação dos cenários 
• Builder e Fluent 
• Load-data 
• Como identificar o que é bom ser testado 
(tudo?). Como criar estes testes?
Preparação dos cenários 
• É o local mais comum para ocorrer duplicação 
de código 
• Favorece o reuso desnecessário de cenários 
• O que podemos fazer?
Preparação dos cenários 
Usar patterns como o Builder e o Fluent ajudam, 
pois: 
• Elimina código desnecessário 
• Evita duplicação 
• Incentiva o reuso dos mesmos valores de 
variáveis entre os testes
Sem Builder e sem Fluent 
public class CompanyTest { 
@Test 
public void testInsertCompany(){ 
Company company = new Company("Mc Donalds", "41.304.875/0001-64"); 
//teste de inserir 
} 
@Test 
public void testUpdateCompany(){ 
Company company = new Company("Company 1", "58.455.457/0001-70"); 
//teste de atualização 
} 
@Test public void testRemoveCompany(){ 
Company company = new Company("ACME", "68.132.955/0001-01"); 
//teste de remoção 
} 
}
Builder com Fluent 
public class CompanyTest { 
@Test public void testInsertCompany(){ 
Company company = CompanyBuilder().build(); 
//teste de inserir 
} 
@Test public void testUpdateCompany(){ 
Company company = CompanyBuilder().build(); 
//teste de atualização 
} 
@Test public void testRemoveCompany(){ 
Company company = CompanyBuilder().withName(“Dextra”).build(); 
//teste de remoção 
} 
}
Builder com Fluent 
public class CompanyBuilder { 
private String cnpj = "41.304.875/0001-64"; 
private String name = "Company Name"; 
public Company build() { 
return new Company().withCnpj(cnpj).withName(name); 
} 
public CompanyBuilder withCnpj(String cnpj) { 
this.cnpj = cnpj; 
return this; 
} 
public CompanyBuilder withName(String name) { 
this.name = name; 
return this; 
} 
}
Load-data 
• O que é? 
• Load-data muito grande, com muitos dados, é 
realmente necessário? 
• Usar informações de um load-data para um 
teste é bom? 
• Se for utilizar um load-data, como fazer isso 
de uma maneira fácil para entendimento e 
construção de um teste?
Load-data 
• Utilização de FIXTURES para facilitar a 
criação de objetos, evitar consultas ao banco 
e garantir a consistência dos dados na 
utilização em testes.
Load-data 
public enum PessoaFixture implements EnumFixture { 
JamesTKirk("JAMES T. KIRK", "JAMES",TipoPessoa.BR,"1986-01-01"); 
public String toInsertString() ; 
public Long getId(); 
public Pessoa toEntidade() { 
return EnumFixtureUtil.preencherAtributos(new Pessoa(), this); 
} 
}
Load-data 
@Test 
public void buscarRestricaoPorPessoaQuandoNaoExistirRestricaoParaAPessoa() 
{ 
RestricaoPessoa restricao = 
repository.buscarPorPessoa(PessoaFixture.JamesTKirk.toEntidade()); 
Assert.assertNull(restricao); 
}
Preparação dos cenários 
• Em testes funcionais ou de integração, é 
comum alguns testes partirem da mesma base 
de informações. Exemplo de uma aplicação 
bancária: exige uma Pessoa, Pessoa Física, 
Usuário, Conta Corrente… 
Como lidar?
Preparação dos cenários 
• Deixar claro os cenários básicos para reuso! 
Exemplo: 
public class PessoaTeste { 
@Test 
public void testeMovimentacaoContaCorrente { 
criarCenarioBasicoPessoaComContaCorrente(); 
//codigo do teste 
} 
public void criarCenarioBasicoPessoaComContaCorrente() { 
// codigo do cenario 
} 
}
Preparação dos cenários 
Alguns alertas sobre preparação de cenários: 
Usar com cautela o @BeforeTest e 
@BeforeClass. São usados apenas quando 
você tem absoluta certeza que TODOS os 
testes precisam do código que pretende colocar 
lá sob estas anotações.
O que testar? 
• Mesmo com TDD, esta pergunta é válida; 
• Teste comportamentos e não métodos;
Testar comportamento x método 
• Depois de escrever um método, é fácil 
escrever um teste que verifica o que ele faz. 
Mas complica se achar que os testes e 
métodos público devem ter relação 1:1 
• Nós queremos realmente é testar o seu 
comportamento!
Teste de método 
@Test public void testProcessTransaction() { 
User user = newUserWithBalance(LOW_BALANCE_THRESHOLD.plus(dollars(2)); 
transactionProcessor.processTransaction(user, new Transaction("Pile of 
Beanie Babies", dollars(3))); 
assertContains("You bought a Pile of Beanie Babies", ui.getText()); 
assertEquals(1, user.getEmails().size()); 
assertEquals("balance is low”, user.getEmails().get(0).getSubject()); 
}
Teste de comportamento 
@Test public void testProcessTransaction_displaysNotification() { 
transactionProcessor.processTransaction( 
new User(), new Transaction("Pile of Beanie Babies")); 
assertContains("You bought a Pile of Beanie Babies", ui.getText()); 
} 
@Test public void testProcessTransaction_sendsEmailWhenBalanceIsLow() { 
User user = newUserWithBalance(LOW_BALANCE_THRESHOLD.plus(dollars(2)); 
transactionProcessor.processTransaction( 
user, 
new Transaction(dollars(3))); 
assertEquals(1, user.getEmails().size()); 
assertEquals("Your balance is low", user.getEmails().get(0).getSubject()); 
}
Você testa o comportamento de suas exceptions? 
@Test(expectedExceptions = ValidacaoException.class) 
public void validarQuandoNaoTemDataBloqueio() throws ValidacaoException { 
Date dataBloqueio = null; 
RestricaoPessoa restricao = new RestricaoPessoa(new Brasileiro(), dataBloqueio, 
OrigemRestricaoPessoa.SOCC, new TipoRestricaoPessoa()); 
restricao.validar(); 
} 
@Test(expectedExceptions = PagamentoMaiorQueTotalAPagarException.class) 
public void addPagamentoEspecieTendoValorMaiorQueDaProposta() throws 
PagamentoMaiorQueTotalAPagarException,PagamentoExcedenteException { 
proposta.valor(BigDecima.valueOf(50l); 
PagamentoEspecie pagamento = new PagamentoEspecie(MoedaFixture.USD, 
BigDecimal.valueOf(100l), proposta, new Venda()); 
proposta.addPagamento(pagamento); 
}
Flexibilidade x Simplicidade 
• Evite colocar código de lógica nos seus testes 
• Nos testes, simplicidade é mais importante 
que flexibilidade!
Flexibilidade x Simplicidade 
Ruim: 
@Test 
public void shouldNavigateToPhotosPage() { 
String baseUrl = "http://plus.google.com/"; 
Navigator nav = new Navigator(baseUrl); 
nav.goToPhotosPage(); 
assertEquals(baseUrl + "/u/0/photos", nav.getCurrentUrl()); 
}
Flexibilidade x Simplicidade 
Bom: 
@Test 
public void shouldNavigateToPhotosPage() { 
Navigator nav = new Navigator(“http://plus.google.com/"); 
nav.goToPhotosPage(); 
assertEquals("http://plus.google.com//u/0/photos", 
nav.getCurrentUrl()); // Oops! 
}
“... if it seems like a simple change to code 
causes excessively long changes to tests, that's 
a sign that there's a problem with the tests. This 
may not be so much that you are testing too 
many things, but that you have duplication in 
your tests….” - Kent Beck 
Resiliência
Cobertura de Testes 
• Porcentagem de cobertura é importante? 
• A cobertura tem seus méritos!
Cobertura de Testes 
• Encontrar código não testado 
• Ter um senso de qual a situação real do 
projeto
E o TDD?! 
• O que é? 
• No que facilita? 
• Qual a dificuldade de usar? 
• Polêmicas!
TDD 
“If you don’t drive development with tests, what do 
you drive it with? Speculation? Specifications (ever 
notice that those two words come from the same 
root?)” 
Kent Beck - TDD by Example
…e os nossos clientes?? 
Como nossos clientes veem a questão dos 
testes? 
Eles acreditam neles tanto quanto nós 
acreditamos? 
Por que quando temos que priorizar algumas 
coisas, acabamos por deixar os testes de lado 
em algumas situações?
Conclusão 
• Simplicidade é muito importante 
• Se algum teste está difícil de manter, ele não 
está bom 
• Trate com carinho o código do teste 
• Escreva seu código de teste pensando como 
um código de business
O que ficou faltando falar... 
• Muita coisa! 
• Quando usar frameworks de mock (Mockito, EasyMock, 
etc) 
• Testes de tela: PhantonJS, Selenium, etc 
• Minimização de bugs não-reproduzíveis 
• Diferença entre fake, mock, stub e dummy 
• Testes de carga
Referências 
• Google Testing Blog 
• Livro Code Complete 
• Métodos ágeis: o que é flolclore e o que é real 
• Is TDD dead?

Mais conteúdo relacionado

Semelhante a Como escrever bons testes! - Dex transforming days

Onde nenhum desenvolvedor jamais testou: Introduzindo testes unitários em cód...
Onde nenhum desenvolvedor jamais testou: Introduzindo testes unitários em cód...Onde nenhum desenvolvedor jamais testou: Introduzindo testes unitários em cód...
Onde nenhum desenvolvedor jamais testou: Introduzindo testes unitários em cód...André Ricardo Barreto de Oliveira
 
Testes Unitários com GTest e Catch
Testes Unitários com GTest e CatchTestes Unitários com GTest e Catch
Testes Unitários com GTest e CatchUilian Ries
 
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOSTDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOSFábio Miranda
 
Exercícios java 20 02
Exercícios java 20   02Exercícios java 20   02
Exercícios java 20 02julyesersantos
 
Introdução a testes unitários com jUnit
Introdução a testes unitários com jUnitIntrodução a testes unitários com jUnit
Introdução a testes unitários com jUnitLeonardo Soares
 
Curso Java Básico - Aula 03
Curso Java Básico - Aula 03Curso Java Básico - Aula 03
Curso Java Básico - Aula 03Natanael Fonseca
 
Teste unitário
Teste unitárioTeste unitário
Teste unitáriodist_bp
 
Palestra Mocks - AgileBrazil 2010
Palestra Mocks - AgileBrazil 2010Palestra Mocks - AgileBrazil 2010
Palestra Mocks - AgileBrazil 2010rafaelferreira
 
Testes de Unidade com JUnit
Testes de Unidade com JUnitTestes de Unidade com JUnit
Testes de Unidade com JUnitelliando dias
 
Testes de regressão automatizados
Testes de regressão automatizadosTestes de regressão automatizados
Testes de regressão automatizadosCristian R. Silva
 
Testes Automatizados de Software
Testes Automatizados de SoftwareTestes Automatizados de Software
Testes Automatizados de SoftwareMaurício Aniche
 
SOLID - Os cinco princípios ágeis de POO
SOLID - Os cinco princípios ágeis de POOSOLID - Os cinco princípios ágeis de POO
SOLID - Os cinco princípios ágeis de POORamon Valerio
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitDiego Tremper
 

Semelhante a Como escrever bons testes! - Dex transforming days (20)

Ganhando tempo com casos de testes
Ganhando tempo com casos de testesGanhando tempo com casos de testes
Ganhando tempo com casos de testes
 
Onde nenhum desenvolvedor jamais testou: Introduzindo testes unitários em cód...
Onde nenhum desenvolvedor jamais testou: Introduzindo testes unitários em cód...Onde nenhum desenvolvedor jamais testou: Introduzindo testes unitários em cód...
Onde nenhum desenvolvedor jamais testou: Introduzindo testes unitários em cód...
 
Testes Unitários com GTest e Catch
Testes Unitários com GTest e CatchTestes Unitários com GTest e Catch
Testes Unitários com GTest e Catch
 
TDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOSTDD - Algumas lições aprendidas com o livro GOOS
TDD - Algumas lições aprendidas com o livro GOOS
 
JUnit
JUnitJUnit
JUnit
 
Testes com JUnit
Testes com JUnitTestes com JUnit
Testes com JUnit
 
Exercícios java 20 02
Exercícios java 20   02Exercícios java 20   02
Exercícios java 20 02
 
Introdução a testes unitários com jUnit
Introdução a testes unitários com jUnitIntrodução a testes unitários com jUnit
Introdução a testes unitários com jUnit
 
Aula5
Aula5Aula5
Aula5
 
Curso Java Básico - Aula 03
Curso Java Básico - Aula 03Curso Java Básico - Aula 03
Curso Java Básico - Aula 03
 
Teste unitário
Teste unitárioTeste unitário
Teste unitário
 
Test driven development
Test driven developmentTest driven development
Test driven development
 
Palestra Mocks - AgileBrazil 2010
Palestra Mocks - AgileBrazil 2010Palestra Mocks - AgileBrazil 2010
Palestra Mocks - AgileBrazil 2010
 
VRaptor4
VRaptor4VRaptor4
VRaptor4
 
Testes de Unidade com JUnit
Testes de Unidade com JUnitTestes de Unidade com JUnit
Testes de Unidade com JUnit
 
Testes de regressão automatizados
Testes de regressão automatizadosTestes de regressão automatizados
Testes de regressão automatizados
 
Ctai Teste De Software Aula 1
Ctai Teste De Software Aula 1Ctai Teste De Software Aula 1
Ctai Teste De Software Aula 1
 
Testes Automatizados de Software
Testes Automatizados de SoftwareTestes Automatizados de Software
Testes Automatizados de Software
 
SOLID - Os cinco princípios ágeis de POO
SOLID - Os cinco princípios ágeis de POOSOLID - Os cinco princípios ágeis de POO
SOLID - Os cinco princípios ágeis de POO
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnit
 

Como escrever bons testes! - Dex transforming days

  • 1. Como escrever bons testes! por Danilo De Luca e Dherik Barison
  • 2. “Trying to improve software quality by increasing the amount of testing is like trying to lose weight by weighing yourself more often” Steve McConnell - Code Complete
  • 3. Motivação • Importância • Pouca conversa aprofundada sobre o tema • Será que realmente sabemos o fazer um teste ser bom... • Falta de visibilidade de que o código de um teste deve ser tão bom quanto um código de “business”
  • 4. O que faz um teste ser bom? • Performance • Manutenabilidade • Clareza • Resiliência • Precisão
  • 5. Como escrever um teste bom? • Testes devem servir como uma documentação do sistema • Os nomes dos testes devem dizer o que eles fazem • Não deve conhecer detalhes de implementação* • Não deve exibir informações que distraiam do objetivo do teste • Um novo comportamento na aplicação não deve alterar os testes antigos, apenas adicionar novos testes
  • 6. Como conseguir um teste bom? Ruim: @Test public void shouldPerformAddition() { Calculator calculator = new Calculator(new RoundingStrategy(), "unused", ENABLE_COSIN_FEATURE, 0.01, calculusEngine, false); int result = calculator.doComputation(makeTestComputation()); assertEquals(5, result); // De onde este número veio? }
  • 7. Como conseguir um teste bom? Ruim: @Test public void shouldPerformAddition() { Calculator calculator = new Calculator(new RoundingStrategy(), "unused", ENABLE_COSIN_FEATURE, 0.01, calculusEngine, false); int result = calculator.doComputation(makeTestComputation()); assertEquals(5, result); // De onde este número veio? }
  • 8. Como conseguir um teste bom? Ruim: @Test public void shouldPerformAddition() { Calculator calculator = new Calculator(new RoundingStrategy(), "unused", ENABLE_COSIN_FEATURE, 0.01, calculusEngine, false); int result = calculator.doComputation(makeTestComputation()); assertEquals(5, result); // De onde este número veio? }
  • 9. Como conseguir um teste bom? Bom: @Test public void shouldPerformAddition() { Calculator calculator = newCalculator(); int result = calculator.doComputation(makeAdditionComputation(2,3)); assertEquals(5, result); }
  • 10. Como conseguir um teste bom? Bom: @Test public void shouldPerformAddition() { Calculator calculator = newCalculator(); int result = calculator.doComputation(makeAdditionComputation(2, 3)); assertEquals(5, result); }
  • 11. Como conseguir um teste bom? Bom: @Test public void shouldPerformAddition() { Calculator calculator = newCalculator(); int result = calculator.doComputation(makeAdditionComputation(2, 3)); assertEquals(5, result); }
  • 12. Como conseguir um teste bom? Ruim: @Test public void isUserLockedOut_invalidLogin() { authenticator.authenticate(username, invalidPassword); assertFalse(authenticator.isUserLockedOut(username)); authenticator.authenticate(username, invalidPassword); assertFalse(authenticator.isUserLockedOut(username)); authenticator.authenticate(username, invalidPassword); assertTrue(authenticator.isUserLockedOut(username)); }
  • 13. Como conseguir um teste bom? Bom: @Test public void isUserLockedOut_lockOutUserAfterThreeInvalidLoginAttempts() { authenticator.authenticate(username, invalidPassword); assertFalse(authenticator.isUserLockedOut(username)); authenticator.authenticate(username, invalidPassword); assertFalse(authenticator.isUserLockedOut(username)); authenticator.authenticate(username, invalidPassword); assertTrue(authenticator.isUserLockedOut(username)); }
  • 14. Quais as dificuldades mais comuns? • Preparação dos cenários • Builder e Fluent • Load-data • Como identificar o que é bom ser testado (tudo?). Como criar estes testes?
  • 15. Preparação dos cenários • É o local mais comum para ocorrer duplicação de código • Favorece o reuso desnecessário de cenários • O que podemos fazer?
  • 16. Preparação dos cenários Usar patterns como o Builder e o Fluent ajudam, pois: • Elimina código desnecessário • Evita duplicação • Incentiva o reuso dos mesmos valores de variáveis entre os testes
  • 17. Sem Builder e sem Fluent public class CompanyTest { @Test public void testInsertCompany(){ Company company = new Company("Mc Donalds", "41.304.875/0001-64"); //teste de inserir } @Test public void testUpdateCompany(){ Company company = new Company("Company 1", "58.455.457/0001-70"); //teste de atualização } @Test public void testRemoveCompany(){ Company company = new Company("ACME", "68.132.955/0001-01"); //teste de remoção } }
  • 18. Builder com Fluent public class CompanyTest { @Test public void testInsertCompany(){ Company company = CompanyBuilder().build(); //teste de inserir } @Test public void testUpdateCompany(){ Company company = CompanyBuilder().build(); //teste de atualização } @Test public void testRemoveCompany(){ Company company = CompanyBuilder().withName(“Dextra”).build(); //teste de remoção } }
  • 19. Builder com Fluent public class CompanyBuilder { private String cnpj = "41.304.875/0001-64"; private String name = "Company Name"; public Company build() { return new Company().withCnpj(cnpj).withName(name); } public CompanyBuilder withCnpj(String cnpj) { this.cnpj = cnpj; return this; } public CompanyBuilder withName(String name) { this.name = name; return this; } }
  • 20. Load-data • O que é? • Load-data muito grande, com muitos dados, é realmente necessário? • Usar informações de um load-data para um teste é bom? • Se for utilizar um load-data, como fazer isso de uma maneira fácil para entendimento e construção de um teste?
  • 21. Load-data • Utilização de FIXTURES para facilitar a criação de objetos, evitar consultas ao banco e garantir a consistência dos dados na utilização em testes.
  • 22. Load-data public enum PessoaFixture implements EnumFixture { JamesTKirk("JAMES T. KIRK", "JAMES",TipoPessoa.BR,"1986-01-01"); public String toInsertString() ; public Long getId(); public Pessoa toEntidade() { return EnumFixtureUtil.preencherAtributos(new Pessoa(), this); } }
  • 23. Load-data @Test public void buscarRestricaoPorPessoaQuandoNaoExistirRestricaoParaAPessoa() { RestricaoPessoa restricao = repository.buscarPorPessoa(PessoaFixture.JamesTKirk.toEntidade()); Assert.assertNull(restricao); }
  • 24. Preparação dos cenários • Em testes funcionais ou de integração, é comum alguns testes partirem da mesma base de informações. Exemplo de uma aplicação bancária: exige uma Pessoa, Pessoa Física, Usuário, Conta Corrente… Como lidar?
  • 25. Preparação dos cenários • Deixar claro os cenários básicos para reuso! Exemplo: public class PessoaTeste { @Test public void testeMovimentacaoContaCorrente { criarCenarioBasicoPessoaComContaCorrente(); //codigo do teste } public void criarCenarioBasicoPessoaComContaCorrente() { // codigo do cenario } }
  • 26. Preparação dos cenários Alguns alertas sobre preparação de cenários: Usar com cautela o @BeforeTest e @BeforeClass. São usados apenas quando você tem absoluta certeza que TODOS os testes precisam do código que pretende colocar lá sob estas anotações.
  • 27. O que testar? • Mesmo com TDD, esta pergunta é válida; • Teste comportamentos e não métodos;
  • 28. Testar comportamento x método • Depois de escrever um método, é fácil escrever um teste que verifica o que ele faz. Mas complica se achar que os testes e métodos público devem ter relação 1:1 • Nós queremos realmente é testar o seu comportamento!
  • 29. Teste de método @Test public void testProcessTransaction() { User user = newUserWithBalance(LOW_BALANCE_THRESHOLD.plus(dollars(2)); transactionProcessor.processTransaction(user, new Transaction("Pile of Beanie Babies", dollars(3))); assertContains("You bought a Pile of Beanie Babies", ui.getText()); assertEquals(1, user.getEmails().size()); assertEquals("balance is low”, user.getEmails().get(0).getSubject()); }
  • 30. Teste de comportamento @Test public void testProcessTransaction_displaysNotification() { transactionProcessor.processTransaction( new User(), new Transaction("Pile of Beanie Babies")); assertContains("You bought a Pile of Beanie Babies", ui.getText()); } @Test public void testProcessTransaction_sendsEmailWhenBalanceIsLow() { User user = newUserWithBalance(LOW_BALANCE_THRESHOLD.plus(dollars(2)); transactionProcessor.processTransaction( user, new Transaction(dollars(3))); assertEquals(1, user.getEmails().size()); assertEquals("Your balance is low", user.getEmails().get(0).getSubject()); }
  • 31. Você testa o comportamento de suas exceptions? @Test(expectedExceptions = ValidacaoException.class) public void validarQuandoNaoTemDataBloqueio() throws ValidacaoException { Date dataBloqueio = null; RestricaoPessoa restricao = new RestricaoPessoa(new Brasileiro(), dataBloqueio, OrigemRestricaoPessoa.SOCC, new TipoRestricaoPessoa()); restricao.validar(); } @Test(expectedExceptions = PagamentoMaiorQueTotalAPagarException.class) public void addPagamentoEspecieTendoValorMaiorQueDaProposta() throws PagamentoMaiorQueTotalAPagarException,PagamentoExcedenteException { proposta.valor(BigDecima.valueOf(50l); PagamentoEspecie pagamento = new PagamentoEspecie(MoedaFixture.USD, BigDecimal.valueOf(100l), proposta, new Venda()); proposta.addPagamento(pagamento); }
  • 32. Flexibilidade x Simplicidade • Evite colocar código de lógica nos seus testes • Nos testes, simplicidade é mais importante que flexibilidade!
  • 33. Flexibilidade x Simplicidade Ruim: @Test public void shouldNavigateToPhotosPage() { String baseUrl = "http://plus.google.com/"; Navigator nav = new Navigator(baseUrl); nav.goToPhotosPage(); assertEquals(baseUrl + "/u/0/photos", nav.getCurrentUrl()); }
  • 34. Flexibilidade x Simplicidade Bom: @Test public void shouldNavigateToPhotosPage() { Navigator nav = new Navigator(“http://plus.google.com/"); nav.goToPhotosPage(); assertEquals("http://plus.google.com//u/0/photos", nav.getCurrentUrl()); // Oops! }
  • 35. “... if it seems like a simple change to code causes excessively long changes to tests, that's a sign that there's a problem with the tests. This may not be so much that you are testing too many things, but that you have duplication in your tests….” - Kent Beck Resiliência
  • 36. Cobertura de Testes • Porcentagem de cobertura é importante? • A cobertura tem seus méritos!
  • 37. Cobertura de Testes • Encontrar código não testado • Ter um senso de qual a situação real do projeto
  • 38. E o TDD?! • O que é? • No que facilita? • Qual a dificuldade de usar? • Polêmicas!
  • 39. TDD “If you don’t drive development with tests, what do you drive it with? Speculation? Specifications (ever notice that those two words come from the same root?)” Kent Beck - TDD by Example
  • 40. …e os nossos clientes?? Como nossos clientes veem a questão dos testes? Eles acreditam neles tanto quanto nós acreditamos? Por que quando temos que priorizar algumas coisas, acabamos por deixar os testes de lado em algumas situações?
  • 41. Conclusão • Simplicidade é muito importante • Se algum teste está difícil de manter, ele não está bom • Trate com carinho o código do teste • Escreva seu código de teste pensando como um código de business
  • 42. O que ficou faltando falar... • Muita coisa! • Quando usar frameworks de mock (Mockito, EasyMock, etc) • Testes de tela: PhantonJS, Selenium, etc • Minimização de bugs não-reproduzíveis • Diferença entre fake, mock, stub e dummy • Testes de carga
  • 43. Referências • Google Testing Blog • Livro Code Complete • Métodos ágeis: o que é flolclore e o que é real • Is TDD dead?

Notas do Editor

  1. Mostrar que não deve existir diferença entre qualidade de código de um teste para um código de “business”. http://googletesting.blogspot.com.br/2014/05/testing-on-toilet-effective-testing.html a resilient test doesn't have to change unless the purpose or behavior of the class being tested changes. Adding new behavior should only require adding new tests, not changing old ones. The original test above isn't resilient since you'll have to update it (and probably dozens of other tests!) whenever you add a new irrelevant constructor parameter. Moving these details into the helper method solved this problem.
  2. * casos raros, como garantir que o sistema está lendo do cache e não do banco de dados
  3. Detalhes desnecessários foram escondidos. O método makeAdditionComputation deixa mais claro.
  4. O método newCalculator() abstrai toda a logica de como instanciar uma “calculadora” deixando o teste simples e claro para quem precisar le-lo
  5. O método newCalculator() abstrai toda a logica de como instanciar uma “calculadora” deixando o teste simples e claro para quem precisar le-lo
  6. Esperar para ver se o pessoal consegue identificar o que este teste faz! http://googletesting.blogspot.com.br/2014/10/testing-on-toilet-writing-descriptive.html
  7. https://github.com/dextra/kroton_empregabilidade/blob/master/implementation/web/src/test/java/br/com/kroton/domain/builder/CompanyBuilder.java
  8. traduzir!
  9. traduzir!
  10. http://googletesting.blogspot.com.br/2014/07/testing-on-toilet-dont-put-logic-in.html
  11. a resilient test doesn't have to change unless the purpose or behavior of the class being tested changes. Adding new behavior should only require adding new tests, not changing old ones. The original test above isn't resilient since you'll have to update it (and probably dozens of other tests!) whenever you add a new irrelevant constructor parameter. Moving these details into the helper method solved this problem.
  12. Argumentar sobre essa frase, que é uma das justificativas para se usar TDD Falar sobre o “is tdd dead”
  13. Argumentar sobre essa frase, que é uma das justificativas para se usar TDD Falar sobre o “is tdd dead”