Palestra Mocks - AgileBrazil 2010

25
Já que vai fingir, finja direito Testando com Mocks Lucas Cavalcanti @lucascs Rafael Ferreira @rafaeldff

description

Slides com dicas para programar usando mocks, apresentadas na conferência AgileBrazil 2010.

Transcript of Palestra Mocks - AgileBrazil 2010

Page 1: Palestra Mocks - AgileBrazil 2010

Já que vai fingir, finja direitoTestando com Mocks

Lucas Cavalcanti @lucascsRafael Ferreira @rafaeldff

Page 2: Palestra Mocks - AgileBrazil 2010

Testes unitários

Page 3: Palestra Mocks - AgileBrazil 2010

Seu código é testável?

public class Programa { public static void executa() { BancoDeDados bd = new BancoDeDados(); EnviadorDeEmail enviador =

new EnviadorDeEmail(); Usuario usuario = Usuario.getAtual(); if (bd.autentica(usuario)) { enviador.enviaEmail(usuario); } }}

Page 4: Palestra Mocks - AgileBrazil 2010

Injeção de dependências

Page 5: Palestra Mocks - AgileBrazil 2010

Código mais testável

public class Mecanico {

public Mecanico(ChaveDeFenda fenda, ChaveInglesa inglesa,CalendarioPorno calendario) {

... }

public void trocaMotor(Carro carro) { try { Motor motor = carro.getMotor(); fenda.remove(motor); } catch (TopadaNoDedaoException e) { xingaMuitoNoTwitter(e); } }

}

Page 6: Palestra Mocks - AgileBrazil 2010

Teste #comofas

Page 7: Palestra Mocks - AgileBrazil 2010

Como criar um Mecanico?

ChaveDeFenda fenda = vaiNaCaixaEBuscaAChaveDeFenda();

ChaveInglesa inglesa = vaiNaCaixaEBuscaAChaveInglesa();

CalendarioPorno calendario = vaiNaLojaECompraOCalendario();

Mecanico mecanico = new Mecanico(fenda, inglesa, calendario);

//resto do teste...

Page 8: Palestra Mocks - AgileBrazil 2010

Mocks

Page 9: Palestra Mocks - AgileBrazil 2010

Como criar um Mecanico?

ChaveDeFenda fenda = mock(ChaveDeFenda.class);

ChaveInglesa inglesa = mock(ChaveInglesa.class);

CalendarioPorno calendario = mock(CalendarioPorno.class);

Mecanico mecanico = new Mecanico(fenda, inglesa, calendario);

//resto do teste...

Page 10: Palestra Mocks - AgileBrazil 2010

Test Smells

Quando seu teste diz que há algo de errado

Page 11: Palestra Mocks - AgileBrazil 2010

Nomes ruins

public class LancadorTest {

public void testDispara() { // coisas complicadas }

}

Page 12: Palestra Mocks - AgileBrazil 2010

Nomes ruins

public class LancadorTest {

public void disparaMisseisQuandoUmAtaqueNuclearForDetectado(){ // coisas escabrosas }

}

X

Page 13: Palestra Mocks - AgileBrazil 2010

Testes muito grandes

public void testEnaganaOCliente() { Parafuseta parafuseta = new Parafuseta(new Estepe()); List<Cavalo> cavalos = Collections.nCopies(123, new Cavalo(Cor.BRANCO)); parafuseta.setMotor(new Motor(cavalos)); Peca rebimbocaDaParafuseta = new Rebimboca(parafuseta); Cliente cliente = mockery.mock(Cliente.class); mockery.checking(new Expectations() {{ one(cliente).recebePreco(Double.MAX_VALUE); one(cliente).recebePreco(Double.MAX_VALUE / 2); one(cliente).naoTemUmJeitinho(true); one(cliente).recebePreco(1.99d); }}); Mecanico mecanico = new Mecanico(); mecanico.forneceOrcamento(rebimbocaDaParafuseta, cliente);}

Page 14: Palestra Mocks - AgileBrazil 2010

Testes muito grandes

public void testEnganaOCliente() { Cliente cliente = mockery.mock(Cliente.class); esperandoNegociacao(cliente);

mecanico.forneceOrcamento(umaPecaInventada(), cliente);}

public void esperandoNegociacao(Cliente cliente) { mockery.checking(new Expectations() {{ one(cliente).recebePreco(Double.MAX_VALUE); one(cliente).recebePreco(Double.MAX_VALUE / 2); one(cliente).naoTemUmJeitinho(true); one(cliente).recebePreco(1.99d); }});

}

public Peca umaPecaInventada() { Parafuseta parafuseta = new Parafuseta(new Estepe()); List<Cavalo> cavalos = Collections.nCopies(123, new Cavalo(Color.BRANCO)); parafuseta.setMotor(new Motor(cavalos)); return new Rebimboca(parafuseta);

}X

Page 15: Palestra Mocks - AgileBrazil 2010

Muitas dependências

public void disparaMisseisNuclearesQuandoAtaqueForDetectado() { DetectorAereo detectorAereo = mock(DetectorAereo.class); DetectorDeSubmarino detectorDeSubmarino = mock(DetectorDeS... ComandoRemoto comandoRemoto = mock(ComandoRemoto.class); SensorDePopularidade sensorDePopularidade = mock(SensorDePo... Gps gpsDoBinLaden = mock(Gps.class); Rebimboca rebimbocaDaParafuseta = mock(Rebimboca.class);

Lancador lancador = new Lancador(detectorAereo, detectorDeSubmarino, comandoRemoto, sensorDePopularidade, gpsDoBinLaden, rebimbocaDaParafuseta);

// coisas cabeludas...}

Page 16: Palestra Mocks - AgileBrazil 2010

Muitas dependências

public void disparaMisseisNuclearesQuandoAtaqueForDetectado() { DetectorDeAtaque detectorDeAtaque = mock(DetectorDeAtaque... Rebimboca rebimbocaDaParafuseta = mock(Rebimboca.class);

Lancador lancador = new Lancador(detectorDeAtaque, rebimbocaDaParafuseta);

// coisas do arco da velha...}

X

Page 17: Palestra Mocks - AgileBrazil 2010

Dependências escondidaspublic class Pedido { private static final int TRES_HORAS = 3*60*60*1000; private Date dataDeCriacao = new Date();

public boolean isExpirado() { long agora = System.currentTimeMillis(); return agora - dataDeCriacao.getTime() < TRES_HORAS; }}

public void testaSeEstaExpiradoDepoisDeTresHoras() throws Exception {

Pedido pedido = new Pedido();

Thread.sleep(TRES_HORAS); //?!

assertTrue(pedido.isExpirado());}

Page 18: Palestra Mocks - AgileBrazil 2010

Dependências escondidaspublic class Pedido { private final Date dataDeCriacao; public Pedido(Relogio relogio) { this.dataDeCriacao = relogio.agora(); }

public boolean isExpirado(Date data) { return data.getTime() - dataDeCriacao.getTime() < TRES_HORAS; }}

public void testaSeEstaExpiradoDepoisDeTresHoras() { final Relogio relogio = mockery.mock(Relogio.class);

mockery.checking(new Expectations() {{ one(relogio).agora(); will(returnValue(tresHorasAtras()); }});

Pedido pedido = new Pedido(relogio); assertTrue(pedido.isExpirado(agora()));}X

Page 19: Palestra Mocks - AgileBrazil 2010

Testes frágeis

@Testpublic void enviaEmailDeSenha() { Usuario usuario = new Usuario(); mockery.checking(new Expectations() {{ one(dao).buscaUsuario(1); one(template).compoeEmailDeSenha(usuario); one(configuracao).servidorSmtp(); one(enviadorDeEmail).envia(servidor, email, usuario); }}); controller.enviaEmailDeSenha(1);}

Page 20: Palestra Mocks - AgileBrazil 2010

Testes frágeis

@Testpublic void enviaEmailDeSenha() { Usuario usuario = new Usuario(); mockery.checking(new Expectations() {{ one(enviadorDeEmail).envia(servidor, email, usuario); }}); controller.enviaEmailDeSenha(1);}

@Beforepublic void setUp() { mockery.checking(new Expectations() {{ allowing(dao).buscaUsuario(1); allowing(template).compoeEmailDeSenha(usuario); allowing(configuracao).servidorSmtp(); }});}

X

Page 21: Palestra Mocks - AgileBrazil 2010

Stubs

Page 22: Palestra Mocks - AgileBrazil 2010

Estilos de teste com Mocks

Page 23: Palestra Mocks - AgileBrazil 2010

Behavior Driven Development

desenvolvendo orientado ao comportamento

Page 24: Palestra Mocks - AgileBrazil 2010

Given

@Testpublic void shouldRollbackActiveTransactions(){ given(transaction.isActive()).willReturn(true);

manager.persist(ANY_ENTITY);

verify(transaction).rollback();}

When

Then

Page 25: Palestra Mocks - AgileBrazil 2010

Obrigado!

Lucas Cavalcanti @lucascsRafael Ferreira @rafaeldff

http://www.caelum.com.br