SlideShare uma empresa Scribd logo
Onde nenhum desenvolvedor 
jamais testou: 
Introduzindo testes unitários 
em código legado 
André Ricardo Barreto de Oliveira 
(“Arbo”) 
Core Software Engineer @ Liferay 
Agilidade@Recife 2014
discover.liferay.com
FINALMENTE 
Seu projeto vai adotar Agile
Em várias empresas perto de você: 
"O Gigantesco Projeto 
Feito Sem Agile" 
10+ anos em produção 
milhares de classes 
… e crescendo! 
milhões de linhas 
de código desktop / web / mobile dúzias de frameworks
Mas e os testes?
Introduzindo 
testes 
em código 
legado 
QA Testes 
Manuais Selenium 
Desenvolvedores 
Banco de Dados 
Spring 
Runner 
customizado
Introduzindo 
testes 
em código 
legado 
QA Testes 
Manuais Selenium 
Desenvolvedores 
Banco de Dados 
Spring 
Runner 
customizado 
?
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
Testes de Caracterização 
Classe não tem testes? 
Escreva um teste que apenas 
documenta o comportamento atual.
Testes de Caracterização 
Feliz com a cobertura? 
Implemente a nova funcionalidade.
public class MassMailingServiceTest 
{ 
! 
@Test 
public void whatcangowrong() 
{ 
new MassMailingService(); 
} 
! 
}
new MassMailingService(); 
DatabaseException: 
! 
Você precisa estar conectado ao banco 
de dados para realizar esta operação!
public MassMailingService() 
{ 
this.limit = 
SettingsFromDatabaseService 
.getLimit(); 
} 
#FAIL 
Que fazer?
Alternativa 1
Alternativa 1 
1. Estudar a documentação do framework
Alternativa 1 
1. Estudar a documentação do framework
Alternativa 1 
1. Estudar a documentação do framework 
2. Instalar / importar / emprestar uma base de dados
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
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
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
Alternativa 2
Quando você pode alterar 
a classe de negócio... 
public MassMailingService( 
Settings settings) // interface 
{ 
this.limit = settings.getLimit(); 
}
@Test 
public void whatcangowrong() 
{ 
Settings s = 
Mockito.mock(Settings.class); 
Mockito.when(s.getLimit()) 
.thenReturn(42); 
new MassMailingService(s); 
}
Quando você não pode 
alterar a classe de negócio... 
@Test 
public void whatcangowrong() 
{ 
PowerMockito.mockStatic( 
SettingsFromDatabaseService.class); 
! 
PowerMockito.stub(method( 
SettingsFromDatabaseService.class, "getLimit")) 
.toReturn(42); 
! 
new MassMailingService(); 
}
Quando você não pode 
alterar a classe de negócio... 
@Test 
public void whatcangowrong() 
{ 
PowerMockito.mockStatic( 
SettingsFromDatabaseService.class); 
! 
PowerMockito.stub(method( 
SettingsFromDatabaseService.class, "getLimit")) 
.toReturn(42); 
! 
new MassMailingService(); 
}
public class MassMailingServiceTest 
{ 
! 
@Test 
public void send() 
{ 
new MassMailingService().send( 
new Message("Hello"), 
"andre.oliveira@liferay.com", 
"andre@arbo.com.br"); 
} 
! 
}
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 (uma) nova 
mensagem em sua caixa postal
public void send( 
Message message, String... targets) 
{ 
for (Address address : targets) 
{ 
RealSMTPSender 
.send(message, address); 
} 
} 
#FAIL
@Test 
public void send() 
{ 
Sender s = Mockito.mock(Sender.class); 
Message message = new Message("Hello"); 
new MassMailingService(s).send(message, 
"andre.oliveira@liferay.com", 
"andre@arbo.com.br"); 
Mockito.verify(s).send(message, 
"andre.oliveira@liferay.com"); 
Mockito.verify(s).send(message, 
"andre@arbo.com.br"); 
}
@Test 
public void send() 
{ 
PowerMockito.mockStatic( 
RealSMTPSender.class); 
Message message = new Message("Hello"); 
new MassMailingService().send(message, 
"andre.oliveira@liferay.com", 
"andre@arbo.com.br"); 
PowerMockito.verifyStatic(); 
RealSMTPSender.send(message, 
"andre.oliveira@liferay.com"); 
PowerMockito.verifyStatic(); 
RealSMTPSender.send(message, 
"andre@arbo.com.br"); 
}
Testes unitários 
com isolamento 
(Martin Fowler) 
http://martinfowler.com/bliki/UnitTest.html
100% de cobertura? 
Sim, é possível!
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
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
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
Resultado: todos os branches de execução 
guardados por testes... 
... e Coragem para evoluir 
código legado com Agile.
Happy testing! André de Oliveira 
“Arbo” 
twiKer.com/arbocombr 
andre.oliveira@liferay.com 
github.com/arboliveira/unit-­‐tests-­‐with-­‐isolaLon 
slidesha.re/1xCS1uY

Mais conteúdo relacionado

Semelhante a Onde nenhum desenvolvedor jamais testou: Introduzindo testes unitários em código legado

TDC2015: Testes em APIs REST com Rest-Assured
TDC2015: Testes em APIs REST com Rest-AssuredTDC2015: Testes em APIs REST com Rest-Assured
TDC2015: Testes em APIs REST com Rest-Assured
Júlio de Lima
 
Programação Orientada a Testes
Programação Orientada a TestesProgramação Orientada a Testes
Programação Orientada a Testes
Gregorio Melo
 
Javascript para CSharpers 4 - POO
Javascript para CSharpers 4 - POOJavascript para CSharpers 4 - POO
Javascript para CSharpers 4 - POOWesley Lemos
 
Paralelize seus testes web e mobile para ter feedbacks mais rápidos
Paralelize seus testes web e mobile para ter feedbacks mais rápidosParalelize seus testes web e mobile para ter feedbacks mais rápidos
Paralelize seus testes web e mobile para ter feedbacks mais rápidos
Elias Nogueira
 
Como escrever bons testes! - Dex transforming days
Como escrever bons testes! - Dex transforming days Como escrever bons testes! - Dex transforming days
Como escrever bons testes! - Dex transforming days
Danilo Pereira De Luca
 
Workshop Microservices - Construindo APIs RESTful com Spring Boot
Workshop Microservices - Construindo APIs RESTful com Spring BootWorkshop Microservices - Construindo APIs RESTful com Spring Boot
Workshop Microservices - Construindo APIs RESTful com Spring Boot
Rodrigo Cândido da Silva
 
Integração continua sem traumas
Integração continua sem traumasIntegração continua sem traumas
Integração continua sem traumas
sabrinajn
 
De a máxima cobertura nos seus testes de API
De a máxima cobertura nos seus testes de APIDe a máxima cobertura nos seus testes de API
De a máxima cobertura nos seus testes de API
Elias Nogueira
 
DevOps Summit Brasil - O que não te contaram sobre Agile Testing
DevOps Summit Brasil - O que não te contaram sobre Agile TestingDevOps Summit Brasil - O que não te contaram sobre Agile Testing
DevOps Summit Brasil - O que não te contaram sobre Agile Testing
Samanta Cicilia
 
cypress.pdf
cypress.pdfcypress.pdf
cypress.pdf
Rafael Martins
 
Desenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App EngineDesenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App Engine
Campus Party Brasil
 
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Carlos Duarte do Nascimento
 
[38º GURU SP] Automação de Testes Web em Ruby com Cucumber e Webdriver
[38º GURU SP] Automação de Testes Web em Ruby com Cucumber e Webdriver[38º GURU SP] Automação de Testes Web em Ruby com Cucumber e Webdriver
[38º GURU SP] Automação de Testes Web em Ruby com Cucumber e Webdriver
Júlio de Lima
 
Caipira agil automacao front end selenium
Caipira agil automacao front end seleniumCaipira agil automacao front end selenium
Caipira agil automacao front end selenium
Qualister
 
Agile Brazil 2018
Agile Brazil 2018Agile Brazil 2018
Agile Brazil 2018
Karla Silva
 
Palestra Testes Unidade Com JUnit
Palestra Testes Unidade Com JUnitPalestra Testes Unidade Com JUnit
Palestra Testes Unidade Com JUnit
Robinson Castilho
 
Workshop Elasticsearch - Android Dev Conference 2016
Workshop Elasticsearch - Android Dev Conference 2016Workshop Elasticsearch - Android Dev Conference 2016
Workshop Elasticsearch - Android Dev Conference 2016
Thiago Barradas
 
Linguagem de Programação Java
Linguagem de Programação JavaLinguagem de Programação Java
Linguagem de Programação Java
thomasdacosta
 
TDD (Resumo)
TDD (Resumo)TDD (Resumo)
TDD (Resumo)
Denis Ferrari
 
Android: testes automatizados e TDD
Android: testes automatizados e TDDAndroid: testes automatizados e TDD
Android: testes automatizados e TDD
Dextra
 

Semelhante a Onde nenhum desenvolvedor jamais testou: Introduzindo testes unitários em código legado (20)

TDC2015: Testes em APIs REST com Rest-Assured
TDC2015: Testes em APIs REST com Rest-AssuredTDC2015: Testes em APIs REST com Rest-Assured
TDC2015: Testes em APIs REST com Rest-Assured
 
Programação Orientada a Testes
Programação Orientada a TestesProgramação Orientada a Testes
Programação Orientada a Testes
 
Javascript para CSharpers 4 - POO
Javascript para CSharpers 4 - POOJavascript para CSharpers 4 - POO
Javascript para CSharpers 4 - POO
 
Paralelize seus testes web e mobile para ter feedbacks mais rápidos
Paralelize seus testes web e mobile para ter feedbacks mais rápidosParalelize seus testes web e mobile para ter feedbacks mais rápidos
Paralelize seus testes web e mobile para ter feedbacks mais rápidos
 
Como escrever bons testes! - Dex transforming days
Como escrever bons testes! - Dex transforming days Como escrever bons testes! - Dex transforming days
Como escrever bons testes! - Dex transforming days
 
Workshop Microservices - Construindo APIs RESTful com Spring Boot
Workshop Microservices - Construindo APIs RESTful com Spring BootWorkshop Microservices - Construindo APIs RESTful com Spring Boot
Workshop Microservices - Construindo APIs RESTful com Spring Boot
 
Integração continua sem traumas
Integração continua sem traumasIntegração continua sem traumas
Integração continua sem traumas
 
De a máxima cobertura nos seus testes de API
De a máxima cobertura nos seus testes de APIDe a máxima cobertura nos seus testes de API
De a máxima cobertura nos seus testes de API
 
DevOps Summit Brasil - O que não te contaram sobre Agile Testing
DevOps Summit Brasil - O que não te contaram sobre Agile TestingDevOps Summit Brasil - O que não te contaram sobre Agile Testing
DevOps Summit Brasil - O que não te contaram sobre Agile Testing
 
cypress.pdf
cypress.pdfcypress.pdf
cypress.pdf
 
Desenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App EngineDesenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App Engine
 
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
 
[38º GURU SP] Automação de Testes Web em Ruby com Cucumber e Webdriver
[38º GURU SP] Automação de Testes Web em Ruby com Cucumber e Webdriver[38º GURU SP] Automação de Testes Web em Ruby com Cucumber e Webdriver
[38º GURU SP] Automação de Testes Web em Ruby com Cucumber e Webdriver
 
Caipira agil automacao front end selenium
Caipira agil automacao front end seleniumCaipira agil automacao front end selenium
Caipira agil automacao front end selenium
 
Agile Brazil 2018
Agile Brazil 2018Agile Brazil 2018
Agile Brazil 2018
 
Palestra Testes Unidade Com JUnit
Palestra Testes Unidade Com JUnitPalestra Testes Unidade Com JUnit
Palestra Testes Unidade Com JUnit
 
Workshop Elasticsearch - Android Dev Conference 2016
Workshop Elasticsearch - Android Dev Conference 2016Workshop Elasticsearch - Android Dev Conference 2016
Workshop Elasticsearch - Android Dev Conference 2016
 
Linguagem de Programação Java
Linguagem de Programação JavaLinguagem de Programação Java
Linguagem de Programação Java
 
TDD (Resumo)
TDD (Resumo)TDD (Resumo)
TDD (Resumo)
 
Android: testes automatizados e TDD
Android: testes automatizados e TDDAndroid: testes automatizados e TDD
Android: testes automatizados e TDD
 

Onde nenhum desenvolvedor jamais testou: Introduzindo testes unitários em código legado

  • 1. Onde nenhum desenvolvedor jamais testou: Introduzindo testes unitários em código legado André Ricardo Barreto de Oliveira (“Arbo”) Core Software Engineer @ Liferay Agilidade@Recife 2014
  • 3. FINALMENTE Seu projeto vai adotar Agile
  • 4. Em várias empresas perto de você: "O Gigantesco Projeto Feito Sem Agile" 10+ anos em produção milhares de classes … e crescendo! milhões de linhas de código desktop / web / mobile dúzias de frameworks
  • 5. Mas e os testes?
  • 6.
  • 7. Introduzindo testes em código legado QA Testes Manuais Selenium Desenvolvedores Banco de Dados Spring Runner customizado
  • 8. Introduzindo testes em código legado QA Testes Manuais Selenium Desenvolvedores Banco de Dados Spring Runner customizado ?
  • 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
  • 10. Testes de Caracterização Classe não tem testes? Escreva um teste que apenas documenta o comportamento atual.
  • 11. Testes de Caracterização Feliz com a cobertura? Implemente a nova funcionalidade.
  • 12.
  • 13. public class MassMailingServiceTest { ! @Test public void whatcangowrong() { new MassMailingService(); } ! }
  • 14. new MassMailingService(); DatabaseException: ! Você precisa estar conectado ao banco de dados para realizar esta operação!
  • 15. public MassMailingService() { this.limit = SettingsFromDatabaseService .getLimit(); } #FAIL Que fazer?
  • 17. Alternativa 1 1. Estudar a documentação do framework
  • 18. Alternativa 1 1. Estudar a documentação do framework
  • 19. Alternativa 1 1. Estudar a documentação do framework 2. Instalar / importar / emprestar uma base de dados
  • 20. 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
  • 21. 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
  • 22. 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
  • 24. Quando você pode alterar a classe de negócio... public MassMailingService( Settings settings) // interface { this.limit = settings.getLimit(); }
  • 25. @Test public void whatcangowrong() { Settings s = Mockito.mock(Settings.class); Mockito.when(s.getLimit()) .thenReturn(42); new MassMailingService(s); }
  • 26. Quando você não pode alterar a classe de negócio... @Test public void whatcangowrong() { PowerMockito.mockStatic( SettingsFromDatabaseService.class); ! PowerMockito.stub(method( SettingsFromDatabaseService.class, "getLimit")) .toReturn(42); ! new MassMailingService(); }
  • 27. Quando você não pode alterar a classe de negócio... @Test public void whatcangowrong() { PowerMockito.mockStatic( SettingsFromDatabaseService.class); ! PowerMockito.stub(method( SettingsFromDatabaseService.class, "getLimit")) .toReturn(42); ! new MassMailingService(); }
  • 28.
  • 29.
  • 30. public class MassMailingServiceTest { ! @Test public void send() { new MassMailingService().send( new Message("Hello"), "andre.oliveira@liferay.com", "andre@arbo.com.br"); } ! }
  • 31. 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 (uma) nova mensagem em sua caixa postal
  • 32. public void send( Message message, String... targets) { for (Address address : targets) { RealSMTPSender .send(message, address); } } #FAIL
  • 33. @Test public void send() { Sender s = Mockito.mock(Sender.class); Message message = new Message("Hello"); new MassMailingService(s).send(message, "andre.oliveira@liferay.com", "andre@arbo.com.br"); Mockito.verify(s).send(message, "andre.oliveira@liferay.com"); Mockito.verify(s).send(message, "andre@arbo.com.br"); }
  • 34. @Test public void send() { PowerMockito.mockStatic( RealSMTPSender.class); Message message = new Message("Hello"); new MassMailingService().send(message, "andre.oliveira@liferay.com", "andre@arbo.com.br"); PowerMockito.verifyStatic(); RealSMTPSender.send(message, "andre.oliveira@liferay.com"); PowerMockito.verifyStatic(); RealSMTPSender.send(message, "andre@arbo.com.br"); }
  • 35. Testes unitários com isolamento (Martin Fowler) http://martinfowler.com/bliki/UnitTest.html
  • 36. 100% de cobertura? Sim, é possível!
  • 37. 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
  • 38. 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
  • 39. 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
  • 40. Resultado: todos os branches de execução guardados por testes... ... e Coragem para evoluir código legado com Agile.
  • 41. Happy testing! André de Oliveira “Arbo” twiKer.com/arbocombr andre.oliveira@liferay.com github.com/arboliveira/unit-­‐tests-­‐with-­‐isolaLon slidesha.re/1xCS1uY