41
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

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

Embed Size (px)

DESCRIPTION

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

Citation preview

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

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

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

discover.liferay.com

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

FINALMENTE

Seu projeto vai adotar Agile

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

Em várias empresas perto de você:

"O Gigantesco Projeto Feito Sem Agile"

10+ anos em produção

milhares de classes

milhões de linhas de código desktop / web / mobile dúzias de frameworks

… e crescendo!

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

Mas e os testes?

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

Introduzindo testes

em código legado

QA Testes Manuais Selenium

Desenvolvedores

Banco de Dados

Spring

Runner customizado

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

Introduzindo testes

em código legado

QA Testes Manuais Selenium

Desenvolvedores

Banco de Dados

Spring

Runner customizado

?

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

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  

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

Testes de Caracterização

Classe não tem testes?

Escreva um teste que apenas documenta o comportamento atual.

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

Testes de Caracterização

Feliz com a cobertura?

Implemente a nova funcionalidade.

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

public class MassMailingServiceTest{!

@Test public void whatcangowrong() { new MassMailingService(); }!

}

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

DatabaseException:!

Você precisa estar conectado ao banco de dados para realizar esta operação!

new MassMailingService();

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

public MassMailingService(){ this.limit = SettingsFromDatabaseService .getLimit();}

#FAIL

Que fazer?

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

Alternativa 1

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

Alternativa 1

1. Estudar  a  documentação  do  framework

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

Alternativa 1

1. Estudar  a  documentação  do  framework

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

Alternativa 1

1. Estudar  a  documentação  do  framework

2. Instalar  /  importar  /  emprestar  uma  base  de  dados

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

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

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

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

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

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

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

Alternativa 2

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

public MassMailingService( Settings settings) // interface{ this.limit = settings.getLimit();}

Quando você pode alterar a classe de negócio...

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

@Testpublic void whatcangowrong(){ Settings s = Mockito.mock(Settings.class); Mockito.when(s.getLimit()) .thenReturn(42); new MassMailingService(s);}

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

@Testpublic 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...

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

@Testpublic 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...

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

public class MassMailingServiceTest{! @Test public void send() { new MassMailingService().send( new Message("Hello"), "[email protected]", "[email protected]"); }!}

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

new MassMailingService().send( new Message("Hello"), "[email protected]", "[email protected]");

30 segundos depois…

Você possui 1 (uma) nova

mensagem em sua caixa postal Você possui 1 (uma) nova

mensagem em sua caixa postal

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

public void send( Message message, String... targets){ for (Address address : targets) { RealSMTPSender .send(message, address); }}

#FAIL

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

@Testpublic void send(){ Sender s = Mockito.mock(Sender.class); Message message = new Message("Hello"); new MassMailingService(s).send(message, "[email protected]", "[email protected]"); Mockito.verify(s).send(message, "[email protected]"); Mockito.verify(s).send(message, "[email protected]");}

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

@Testpublic void send(){ PowerMockito.mockStatic( RealSMTPSender.class); Message message = new Message("Hello"); new MassMailingService().send(message, "[email protected]", "[email protected]"); PowerMockito.verifyStatic(); RealSMTPSender.send(message, "[email protected]"); PowerMockito.verifyStatic(); RealSMTPSender.send(message, "[email protected]");}

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

Testes unitários com isolamento

http://martinfowler.com/bliki/UnitTest.html

(Martin Fowler)

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

100% de cobertura? Sim, é possível!

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

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

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

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

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

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

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

Resultado: todos os branches de execução guardados por testes...

...  e  Coragem  para  evoluir  código  legado  com  Agile.

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

Happy testing! André de Oliveira“Arbo”

[email protected]

twiKer.com/arbocombr

github.com/arboliveira/unit-­‐tests-­‐with-­‐isolaLon

_