Top Banner
Escrevendo testes unitários para código legado: técnicas de isolamento André Ricardo Barreto de Oliveira (“Arbo") Core Software Engineer @ Liferay
37

Escrevendo testes unitários para código legado: técnicas de isolamento

Mar 17, 2018

Download

Engineering

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Escrevendo testes unitários para código legado: técnicas de isolamento

Escrevendo testes unitários para código legado: técnicas de isolamento

André Ricardo Barreto de Oliveira (“Arbo")Core Software Engineer @ Liferay

Page 2: Escrevendo testes unitários para código legado: técnicas de isolamento

discover.liferay.com/tdc2014

Page 3: Escrevendo testes unitários para código legado: técnicas de isolamento

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

Page 4: Escrevendo testes unitários para código legado: técnicas de isolamento

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!

Page 5: Escrevendo testes unitários para código legado: técnicas de isolamento

Mas e os testes?

“Veja bem…"

Page 6: Escrevendo testes unitários para código legado: técnicas de isolamento
Page 7: Escrevendo testes unitários para código legado: técnicas de isolamento

Projetos Java Gigantescos

QATestes

ManuaisSelenium

Desenvolvedores

Banco de Dados

Spring

Runner customizado

Page 8: Escrevendo testes unitários para código legado: técnicas de isolamento

SEM TESTES?

SEM PROBLEMAS :)

Page 9: Escrevendo testes unitários para código legado: técnicas de isolamento

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: Escrevendo testes unitários para código legado: técnicas de isolamento

Testes de Caracterização

Classe não tem testes?

Escreva um teste que apenas documenta o comportamento atual.

Page 11: Escrevendo testes unitários para código legado: técnicas de isolamento

Testes de Caracterização

Feliz com a cobertura?

Implemente a nova funcionalidade.

Page 12: Escrevendo testes unitários para código legado: técnicas de isolamento
Page 13: Escrevendo testes unitários para código legado: técnicas de isolamento

public class MassMailingServiceTest{!

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

}

Page 14: Escrevendo testes unitários para código legado: técnicas de isolamento

new MassMailingService();

DatabaseException:!

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

Page 15: Escrevendo testes unitários para código legado: técnicas de isolamento

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

#FAIL

Que fazer?

Page 16: Escrevendo testes unitários para código legado: técnicas de isolamento

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 17: Escrevendo testes unitários para código legado: técnicas de isolamento

Alternativa 2

Page 18: Escrevendo testes unitários para código legado: técnicas de isolamento

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

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

Page 19: Escrevendo testes unitários para código legado: técnicas de isolamento

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

Page 20: Escrevendo testes unitários para código legado: técnicas de isolamento

@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 21: Escrevendo testes unitários para código legado: técnicas de isolamento
Page 22: Escrevendo testes unitários para código legado: técnicas de isolamento

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

Page 23: Escrevendo testes unitários para código legado: técnicas de isolamento

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 24: Escrevendo testes unitários para código legado: técnicas de isolamento

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

#FAIL

Page 25: Escrevendo testes unitários para código legado: técnicas de isolamento

@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 26: Escrevendo testes unitários para código legado: técnicas de isolamento

@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 27: Escrevendo testes unitários para código legado: técnicas de isolamento

Testes unitários com isolamento

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

Martin Fowler

Page 28: Escrevendo testes unitários para código legado: técnicas de isolamento

Isolamento e legado

Testes de Caracterização? Código legado, sem testes?

Isolamento vai te ajudar

Page 29: Escrevendo testes unitários para código legado: técnicas de isolamento

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/

Page 30: Escrevendo testes unitários para código legado: técnicas de isolamento

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

Page 31: Escrevendo testes unitários para código legado: técnicas de isolamento

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 32: Escrevendo testes unitários para código legado: técnicas de isolamento

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 33: Escrevendo testes unitários para código legado: técnicas de isolamento

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 34: Escrevendo testes unitários para código legado: técnicas de isolamento

Resultado: cobertura de todos os branches de execução

!

Novas funcionalidades /Refactorings

Page 35: Escrevendo testes unitários para código legado: técnicas de isolamento

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

Page 36: Escrevendo testes unitários para código legado: técnicas de isolamento

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

Page 37: Escrevendo testes unitários para código legado: técnicas de isolamento

Happy testing!André Oliveira

[email protected]

twitter.com/arbocombr

github.com/arboliveira/unit-tests-with-isolation