Loading…

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

Like this presentation? Why not share!

Um bate-papo sobre TDD

on

  • 6,670 views

Apresentação sobre TDD e design, feita no DNAD 2010.

Apresentação sobre TDD e design, feita no DNAD 2010.

Statistics

Views

Total Views
6,670
Views on SlideShare
1,992
Embed Views
4,678

Actions

Likes
2
Downloads
65
Comments
0

7 Embeds 4,678

http://www.aniche.com.br 4474
http://sandysnunes.wordpress.com 189
http://blog.sinhorinho.com 6
http://webcache.googleusercontent.com 3
http://www.linkedin.com 3
http://translate.googleusercontent.com 2
http://theoldreader.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • <br />
  • <br />
  • quem aqui faz tdd? quem aqui nao faz tdd? <br />
  • pratica de desenvolvimento de software popularizada pelo kent beck em 2001 <br /> a mec&#xE2;nica &#xE9; simples: voc&#xEA; deve escrever um teste antes de escrever o c&#xF3;digo de produ&#xE7;&#xE3;o <br />
  • muitas! <br /> diferentes perspectivas <br />
  • testes automatizados s&#xE3;o bons! queremos isso! <br />
  • refatorar com testes automatizados &#xE9; muito f&#xE1;cil e seguro! <br /> medo ao refatorar sem isso! <br />
  • tem teste no nome... <br /> muitas defini&#xE7;&#xF5;es confusas... <br />
  • provando por teoria dos conjuntos.. eles n&#xE3;o tem nada em comum a n&#xE3;o ser os testes de unidade! nenhum livro de TDD fala sobre elas! <br /> - vc pensa em muitas outras coisas quando quer testar! <br />
  • <br />
  • isso mesmo! parece maluquisse? <br />
  • e pensar eh bom! :) <br />
  • s&#xF3; de escrever tr&#xEA;s linhas de c&#xF3;digo, eu penso sobre um monte de coisa... <br />
  • o teste &#xE9; o primeiro cliente <br /> - muitas vezes voc&#xEA; est&#xE1; mudando um c&#xF3;digo que nem existe ainda! <br />
  • TDD &#xE9; uma das pr&#xE1;ticas que te d&#xE3;o feedback mais r&#xE1;pido sobre o seu c&#xF3;digo! <br /> - s&#xF3; perde pra programa&#xE7;&#xE3;o pareada!! <br />
  • TDD diz explicitamente que voc&#xEA; deve fazer sempre o mais simples poss&#xED;vel. Se seguirmos isso, teremos c&#xF3;digo simples, que &#xE9; legal! :) <br />
  • o que voc&#xEA;s gostariam de por numa classe dessa? <br />
  • grande parte da simplicidade eh baseado nisso! chega de adivinha&#xE7;&#xE3;o! o programador s&#xF3; escreve o que realmente precisa! <br />
  • mas daqui a pouco eu critico a maneira que as pessoas entendem isso! <br />
  • claro que n&#xE3;o n&#xE9;! nao existe bala de prata! <br />
  • tdd n&#xE3;o vai resolver seus problemas de design! <br />
  • - vai escrever um c&#xF3;digo que seja f&#xE1;cil de testar... <br /> - existe uma sintonia muito grande entre c&#xF3;digo f&#xE1;cil de testar, e c&#xF3;digo de alta qualidade <br />
  • pq isso acontece? pq voc&#xEA; come&#xE7;a a receber as depend&#xEA;ncias da classe, geralmente pelo construtor! se vc n&#xE3;o faz isso, voc&#xEA; n&#xE3;o consegue testar! <br /> - uncle bob diz que gerenciar dependencias eh a parte mais complicada do desenv de sw <br />
  • voc&#xEA; escreve classes mais f&#xE1;ceis de serem usadas.. os comportamentos s&#xE3;o mais f&#xE1;ceis de serem invocados, voc&#xEA; n&#xE3;o quer perder tempo configurando o objeto pra usar e etc! <br />
  • se voc&#xEA; pergunta pra todo mundo qual a vantagem de TDD, todo mundo diz: &#xE9; receber as depend&#xEA;ncias pelo construtor! agora fica f&#xE1;cil injetar qualquer coisa l&#xE1;! <br />
  • <br />
  • ele evidencia os problemas do seu design <br />
  • eh voc&#xEA;, programador, que resolve o problema! <br />
  • se voc&#xEA; conseguir ver o problema, j&#xE1; &#xE9; meio caminho andado!! <br /> ver &#xE9; a parte mais dif&#xED;cil ! <br />
  • a maioria deles voc&#xEA; percebe basicamente quando est&#xE1; dif&#xED;cil testar! eu, preguicoso, nao quero escrever muito c&#xF3;digo no meu teste, nao quero pensar muito ali... se eu tenho que pensar muito, algo t&#xE1; errado! <br />
  • uma God Class &#xE9; uma classe que &#xE9; acoplada com outras 20 classes... ela conhece um monte de classes, geralmente coordena trabalhos, mas n&#xE3;o tem intelig&#xEA;ncia nenhuma... <br /> <br />
  • explica o c&#xF3;digo <br />
  • veja que a classe CounterPartyFinder &#xE9; usada apenas pela MessageUnpacker... Pq n&#xE3;o passar a depend&#xEA;ncia pra ela? <br />
  • Agora podemos ver que essa regra de neg&#xF3;cio pode ser encapsulada dentro de outro objeto menor e mais espec&#xED;fico, com um nome que fa&#xE7;a sentido ao dom&#xED;nio... <br />
  • yay! <br />
  • TDD tem tudo a ver com depend&#xEA;ncias! eu jah falei que ajuda a pensar melhor nelas? pois &#xE9;... <br />
  • softwares de gente grande s&#xE3;o gigantes e vai ser inevit&#xE1;vel acoplar classe com classe... <br /> a diferen&#xE7;a &#xE9; que TDD faz com que voc&#xEA; acople de uma maneira diferente.. <br />
  • classes estaveis sao classes que tem menos chance de mudar! imagina uma interface com 10 classes que a implementa? voc&#xEA; nunca vai mud&#xE1;-la, certo? <br /> agora imagina depender de uma classe chamada DriverDaEpson? a chance de mudar &#xE9; grande, concorda? Porque voc&#xEA; n&#xE3;o liga de acoplar com IList? <br />
  • logo, queremos acoplar com classes mais est&#xE1;veis do que a classe cliente. Devemos ir sempre em dire&#xE7;&#xE3;o &#xE0; estabilidade. TDD ajuda nisso, j&#xE1; que voc&#xEA; pensa melhor na interface que voc&#xEA; precisa depender, e isso geralmente produz interfaces/classes mais est&#xE1;veis. <br />
  • voc&#xEA; come&#xE7;a a observar diferentes tipos de depend&#xEA;ncias <br /> - dependencies, notifications e adjustments <br />
  • dependencies voc&#xEA; deve tomar cuidado! elas s&#xE3;o imprescindiveis pro seu sistema! ent&#xE3;o tente ao maximo acoplar com classes est&#xE1;veis! <br /> - notifications de alguma forma podem ser removidas do c&#xF3;digo, e extra&#xED;das, como no exemplo... <br />
  • parecem notifiers, n&#xE3;o? <br />
  • lembra do SRP? <br />
  • refatorado para observer... agora quem quiser ser notificado sobre a geracao da nota, torna-se um observer, e ser&#xE1; notificado assim que a nota for gerada... isso desacopla o GeradorDeNotaFiscal do resto do processo, e permite que evolua de maneira mais f&#xE1;cil! <br />
  • se vc sente necessidade de testar um m&#xE9;todo privado, &#xE9; pq provavelmente essa classe n&#xE3;o est&#xE1; coesa! ela tem coisa demais, e vc sente necessidade de testar essas responsabilidades separadas. <br />
  • voc&#xEA; come&#xE7;a a extrair esses comportamentos e colocar em classes menores e mais coesas!! <br />
  • &#xE9; mais f&#xE1;cil compor comportamentos do que criar uma classe com todos os comportamentos <br />
  • imagina agora para escrever todos os testes.. era complicado! precis&#xE1;vamos extrair o comportamento para algum lugar... <br /> - outro exemplo: criar filtros... se tal campo foi postado, ent&#xE3;o adicione isso na condi&#xE7;&#xE3;o, e por a&#xED; vai... <br />
  • a primeira refatoracao eh levar cada filtro para uma classe especifica (depois pode ter uma factory para montar os filtros)... <br /> veja que ficou facil customizar o comportamento de um filtro, al&#xE9;m de ser muito mais f&#xE1;cil testar: agora o n&#xFA;mero de combina&#xE7;&#xF5;es para cada um deles &#xE9; muito menor! <br />
  • classes pequenas sao mais simples! <br />
  • a ideia &#xE9; dar passos de beb&#xEA; em dire&#xE7;&#xE3;o &#xE0; solu&#xE7;&#xE3;o mais simples <br />
  • - a ideia de ficar retornando constantes e acrescentando um monte de if &#xE9; besteira! <br /> - o proprio kent beck diz que nao faz assim <br />
  • - o objetivo principal &#xE9; a solu&#xE7;&#xE3;o mais simples e n&#xE3;o a mudan&#xE7;a mais simples! <br />
  • implementa&#xE7;&#xE3;o voc&#xEA; refatora mais f&#xE1;cil ! design &#xE9; dif&#xED;cil refatorar! <br /> - ao implementar uma funcionalidade, voc&#xEA; deve refatorar o c&#xF3;digo (e o design) para permitir que essa funcionalidade seja adicionada da maneira mais f&#xE1;cil poss&#xED;vel. <br />
  • - acoplamento muito forte <br /> - nao d&#xE1; pra substituir sem m&#xE1;gica! <br /> - quero evoluir sem precisar mexer em c&#xF3;digo que j&#xE1; existe (OCP) <br />
  • - deve-se tomar cuidado para n&#xE3;o deixar o conceito vazar da classe <br />
  • veja a API do asp.net mvc! Precisa mockar muita coisa para testar o HttpRequest <br />
  • - deve-se pensar na melhor abstra&#xE7;&#xE3;o <br /> - lei de demeter <br />
  • - Tell, Don&#x2019;t Ask <br />
  • ajuda a entender o requisito melhor, e isso gera c&#xF3;digo mais perto do dom&#xED;nio <br /> - levantado como uma das partes mais ben&#xE9;ficas do processo pelas pessoas no encontro &#xE1;gil <br />
  • classes que voc&#xEA; n&#xE3;o consegue dar um bom nome tem algo errado... talvez o conceito n&#xE3;o esteja muito claro! <br />
  • ou&#xE7;a eles! eles tem muito a dizer! <br />
  • <br />
  • <br />
  • <br />

Um bate-papo sobre TDD Um bate-papo sobre TDD Presentation Transcript

  • Test-Driven Development e sua Influência no Design Mauricio Aniche http://www.aniche.com.br @mauricioaniche
  • Um bate-papo sobre Test-Driven Development Mauricio Aniche http://www.aniche.com.br @mauricioaniche
  • uma enquete bem rapidinha! View slide
  • o que é TDD? View slide
  • qual a vantagem disso?
  • um conjunto de testes de unidade...
  • e por consequência, segurança!
  • então TDD é uma prática de testes de software?
  • livros sobre livros sobre testes de software TDD testes de baby integração steps red- testes green- análise do de refactor valor-limite unidade feedback classes de no design equivalência
  • ufa, mas hoje todo mundo já sabe!
  • mas como assim... escrevo testes, mas não quero testar?
  • faz o programador pensar sobre um monte de coisas...
  • [TestFixture] public class GeradorDeNotaFiscalTest { [Test] public void DeveGerarUmaNotaFiscal { var gerador = new GeradorDeNotaFiscal(); var nf = gerador.gera(fatura); Assert.AreEqual(fatura.Valor * 0.2, nf.ValorImposto); } } - hmm... ele depende de algo? - deve receber uma fatura? - o nome do método está claro? - o que ele deve retornar?
  • ... e mudar de ideia é “barato”!
  • feedback rápido
  • simplicidade
  • public class CarrinhoDeCompras { // quais atributos? // quais comportamentos? }
  • chega de adivinhação!
  • (mas espera aí que daqui a pouco conversamos sobre isso!)
  • TDD vai salvar o mundo! (WTF?)
  • TDD não faz mágica! :-(
  • mas pra conseguir escrever um teste você...
  • ... deixe as dependências explícitas
  • ... implemente “bons vizinhos”
  • a voz do povo é a voz de Deus?
  • mas não é só isso...
  • TDD mostra os problemas...
  • ... mas quem resolve o problema é você!
  • mas primeiro precisamos ver o problema!
  • ser preguiçoso às vezes é bom!
  • exemplo: como testar uma God class?
  • Bloated constructor Sintoma: A classe possui um alto acoplamento, e isso pode ser visto através do número de parâmetros que a classe recebe no construtor, por exemplo. [TestFixture] public class MessageProcessorTest { [Test] public void ShouldDoSomething() { var processor = new MessageProcessor(unpacker, auditer, locationFinder, counterPartyFinder, domesticNotifier, importedNotifier); processor.OnMessage(BuildSomeSpecificRawMessage()); // algumas assercoes aqui.. } }
  • Bloated constructor public class MessageProcessor { public MessageProcessor(MessageUnpacker unpacker, AuditTrail auditer, CounterPartyFinder counterpartyFinder, LocationFinder locationFinder, DomesticNotifier domesticNotifier, ImportedNotifier importedNotifier) { // seta os atributos aqui } public void OnMessage(Message rawMessage) { UnpackedMessage unpacked = unpacker.Unpack(rawMessage, counterpartyFinder); auditer.RecordReceiptOf(unpacked); // ... if (locationFinder.IsDomestic(unpacked)) { domesticNotifier.Notify(unpacked.AsDomesticMessage()); } else { importedNotifier.Notify(unpacked.AsImportedMessage()); } } }
  • Bloated constructor public class MessageProcessor { public MessageProcessor(MessageUnpacker unpacker, AuditTrail auditer, LocationFinder locationFinder, DomesticNotifier domesticNotifier, ImportedNotifier importedNotifier) { // seta os atributos aqui } public void OnMessage(Message rawMessage) { UnpackedMessage unpacked = unpacker.Unpack(rawMessage); auditer.RecordReceiptOf(unpacked); // ... if (locationFinder.IsDomestic(unpacked)) { domesticNotifier.Notify(unpacked.AsDomesticMessage()); } else { importedNotifier.Notify(unpacked.AsImportedMessage()); } } }
  • Bloated constructor public class MessageProcessor { public MessageProcessor(MessageUnpacker unpacker, AuditTrail auditer, MessageDispatcher dispatcher) { // seta os atributos aqui } public void OnMessage(Message rawMessage) { UnpackedMessage unpacked = unpacker.Unpack(rawMessage); auditer.RecordReceiptOf(unpacked); // ... dispatcher.Dispatch(unpacked); } }
  • por falar em dependências...
  • só diminuir o acoplamento não é suficiente!
  • classes estáveis http://www.aniche.com.br/2010/10/tdd-diminui-o-acoplamento-mas-so-isso-nao-resolve/
  • boas dependências http://www.aniche.com.br/2010/10/tdd-diminui-o-acoplamento-mas-so-isso-nao-resolve/
  • e todas dependências são iguais?
  • você pode então tratá-las de maneiras diferentes!
  • Mocks que não são usados diretamente pelo teste Sintoma: Você passa um mock, seta uma expectativa para ele, mas acaba não os usando nas asserções do teste. [TestFixture] public class GeradorDeNotaFiscal public class GeradorDeNotasFiscaisTest { { public GeradorDeNotaFiscal [Test] public void DeveEnviarAoSap() (InformacoesFiscais info, Sap sap, { EnviadorDeEmail emails) var nf = gerador.gera(fatura); { // seta atributos } sap.Verify(s => s.EnviaNota(nf), Times.Once()); public NotaFiscal Gera(Fatura } fatura) { var [Test] public void nota=geraNotaUsandoInfo(); DeveEnviarOEmail(){ var nf = gerador.gera(fatura); sap.EnviaNota(nota); emails.Verify(s => emails.EnviaNota(nota); s.EnviaNota(nf), Times.Once()); } } } }
  • classes com baixo acoplamento e alta coesão
  • public class GeradorDeNotaFiscal { private IList<IObservadorDeNotaGerada> observadores; public GeradorDeNotaFiscal (InformacoesFiscais info) { ... } public void AdicionaObservador(IObservadorDeNotaGerada observador) { ... } private void Notifica(NotaFiscal nota) { ... } public NotaFiscal Gera(Fatura fatura) { var nota = geraNotaUsandoInformacoesFiscais(); Notifica(nota); } }
  • você já pensou em testar métodos privados? http://www.aniche.com.br/2010/11/voce-quer-testar-metodos-privados-certeza/
  • extrair classes passa a ser normal! http://www.aniche.com.br/2010/11/voce-quer-testar-metodos-privados-certeza/
  • a composição tende a ser mais simples que a soma das partes
  • Testando combinações Sintoma: Os testes passam a ficar complicados e você passa a testar diferentes combinações de entradas. public IList<Fatura> PegaFaturas() { var lista = repositorio.PegaTodasFaturas(); lista = RemoveAntigas(lista); lista = RemovePagas(lista); lista = RemoveQuemTemContatoComercial(lista); return lista; } [Test] public void DeveRemoverAntigas() { MockaRepositorioParaDevolvarListaComFaturasAntigas(); var lista = PegaFaturas(); Assert.VerificaQueSóTemFaturasAntigas(); } [Test] public void DeveRemoverPagas() { MockaRepositorioParaDevolvarListaComFaturasPagas(); var lista = PegaFaturas(); Assert.VerificaQueSóTemFaturasPagas(); }
  • public IList<Fatura> PegaFaturas() { var lista = repositorio.PegaTodasFaturas(); return new RemoveAntigas( new RemovePagas( new RemoveQuemTemContatoComercial())).Filtra(lista); } public class RemoveAntigas : FiltroDeFatura { public RemoveAntigas(FiltroDeFatura) { ... } public RemoveAntigas() { ... } public Filtra(IList<Fatura> faturas) { // filtra e passa para o proximo! } } ...
  • simplicidade é essencial!
  • e o tal dos baby steps?
  • isso é muito mal interpretado! http://blog.caelum.com.br/2010/11/18/mudancas-simples-x-solucoes-simples/
  • A mudança mais simples para resolver um problema não é necessariamente a solução mais simples para resolvê-lo. by @mauricioaniche e @guilhermecaelum http://blog.caelum.com.br/2010/11/18/mudancas-simples-x-solucoes-simples/
  • o problema não é a implementação, e sim o design! http://www.aniche.com.br/2010/11/cuidado-com-seus-baby-steps/
  • um outro problema, aliás, são os tais singletons!
  • encapsulamento não é tão fácil quanto parece!
  • Mocks de mocks de mocks... Sintoma: Você precisa fazer mocks de mocks (de mocks ...) para conseguir testar o que precisa. [TestFixture]     public class AcceptPostPutAndPatchVerbsTests     {         // atributos [SetUp]         public void SetupAContext()         {             httpContext = new Mock<HttpContextBase>();             httpRequest = new Mock<HttpRequestBase>();             requestContext = new RequestContext(httpContext.Object, new RouteData());             controllerContext = new ControllerContext(httpContext.Object, new RouteData(), new SomeController());             httpContext.Setup(h => h.Request).Returns(httpRequest.Object);             context = new ActionExecutingContext(controllerContext, new Mock<ActionDescriptor>().Object, new RouteValueDictionary()) { RequestContext = requestContext };         } [Test]         public void ShouldAcceptPost()         {             httpRequest.Setup(h => h.HttpMethod).Returns("POST");             Assert.IsTrue(new AcceptPostPutAndPatchVerbs().IsValid(context));         }     }
  • abstração é o segredo!
  • Intimidade Inapropriada Sintoma: Você testa classes (geralmente com o péssimo sufixo “Service”) que praticamente só lidam com uma classe específica. [TestFixture] public class EmiteBoletoServiceTest { [Test] public void DeveMarcarOBoletoComoEmitido () { var service = new EmiteBoletoService(); var boleto = new Boleto { Pago = true }; service.Emite(boleto); Assert.AreEqual(true, boleto.Emitido); } public class EmiteBoletoService } { public Emite(Boleto boleto) { if(boleto.Pago) { boleto.Emitido = true; } } }
  • melhor entendimento dos requisitos (pensou que as vantagens tinham acabado?)
  • Impl classes are meaningless
  • Ouça os seus testes! :)
  • Test-driven development (TDD) is the craft of producing automated tests for production code, and using that process to drive design and programming. For every tiny bit of functionality in the production code, you first develop a test that specifies and validates what the code will do.You then produce exactly as much code as will enable that test to pass.Then you refactor (simplify and clarify) both the production code and the test code. www.agilealliance.org/programs/roadmaps/Roadmap/tdd/tdd_index.htm
  • Referências - Freeman, S.; Pryce, N. “Growing Object Oriented Software, Guided By Tests.” - Beck, K. “Test-Driven Development by Example” - Gamma, E.; Helm, R.; Johnson, R.; Vlissides, J. “Design Patterns: Elements of Reusable Object-Oriented Software” - Feathers, M. “Working Effectively with Legacy Code” - Martin, R. “Agile Principles, Patterns, and Practices in C#” - Martin, R. “Clean Code”
  • Obrigado! Mauricio Aniche http://www.aniche.com.br @mauricioaniche