SlideShare uma empresa Scribd logo
Test-Driven Development e
  sua Influência no Design
           Mauricio Aniche
      http://www.aniche.com.br
Mas o que é
TDD mesmo?
Red - Green - Refactor
É sobre testes?
NÃO!
É sobre design!
Mas que confusão!
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
mas todo mundo
já sabe que tdd é sobre
         design!
TDD mostra o
problema, mas não
 resolve pra você!
E como ele ajuda?
[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?
[TestFixture]
public class GeradorDeNotaFiscalTest
{
    [Test]
    public void DeveGerarUmaNotaFiscalEAgruparPorAliquota {
         var gerador = new GeradorDeNotaFiscal();
         var notas = gerador.gera(faturaComServicosComAliquotasDiferentes());
         Assert.AreEqual(1, notas.Count);
    }

    [Test]
    public void DeveGerarUmaNotaFiscalEAgruparPorSerie {
        var gerador = new GeradorDeNotaFiscal();
        var notas = gerador.gera(faturaComServicosComSeriesDiferentes());
        Assert.AreEqual(1, notas.Count);
    }
}                                                 hmm... esse agrupamento é complicado!
                                                   a implementação tá confusa por causa
                                                                     dele...
                                                             já sei! vou extrair!
[TestFixture]
public class GeradorDeNotaFiscalTest
{
    [Test]
    public void DeveGerarUmaNotaFiscal {
         var agrupador = new Mock<IAlgoritmoDeAgrupamento>();
         var gerador = new GeradorDeNotaFiscal(agrupador.Object);
         var notas = gerador.gera(fatura);
         Assert.AreEqual(1, notas.Count);
    }
}




                                                                    nice!
mas não é fácil!
na primeira vez...
public class Carro
{
   public Carro ()
   {
   }
}
public class Carro
{
   private Pneus pneuDianteiro;

    public Carro (Pneus pneuDianteiro)
    {
       this.pneuDianteiro = pneuDianteiro;
    }
}
public class Carro
{
   private Pneus pneuDianteiro;
   private Pneus pneuTraseiro;

    public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro)
    {
       this.pneuDianteiro = pneuDianteiro;
       this.pneuTraseiro = pneuTraseiro;
    }
}
public class Carro
   {
      private Pneus pneuDianteiro;
      private Pneus pneuTraseiro;
      private Suspensao suspensao;

       public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao
suspensao)
       {
           this.pneuDianteiro = pneuDianteiro;
           this.pneuTraseiro = pneuTraseiro;
           this.suspensao = suspensao;
       }
   }
public class Carro
   {
      private Pneus pneuDianteiro;
      private Pneus pneuTraseiro;
      private Suspensao suspensao;
      private Motor motor;

       public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao
suspensao, Motor motor)
       {
          this.pneuDianteiro = pneuDianteiro;
          this.pneuTraseiro = pneuTraseiro;
          this.suspensao = suspensao;
          this.motor = motor;
       }
   }
public class Carro
   {
      private Pneus pneuDianteiro;
      private Pneus pneuTraseiro;
      private Suspensao suspensao;
      private Motor motor;
      private Freio freio;

       public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao
suspensao, Motor motor, Freio freio)
       {
          this.pneuDianteiro = pneuDianteiro;
          this.pneuTraseiro = pneuTraseiro;
          this.suspensao = suspensao;
          this.motor = motor;
          this.freio = freio;
       }
   }
public class Carro
   {
      private Pneus pneuDianteiro;
      private Pneus pneuTraseiro;
      private Suspensao suspensao;
      private Motor motor;
      private Freio freio;
      private CaixaDeCambio caixaDeCambio;

       public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao
suspensao, Motor motor, Freio freio, CaixaDeCambio caixaDeCambio)
       {
          this.pneuDianteiro = pneuDianteiro;
          this.pneuTraseiro = pneuTraseiro;
          this.suspensao = suspensao;
          this.motor = motor;
          this.freio = freio;
          this.caixaDeCambio = caixaDeCambio;
       }
   }
public class Carro
   {
      private Pneus pneuDianteiro;
      private Pneus pneuTraseiro;
      private Suspensao suspensao;
      private Motor motor;
      private Freio freio;
      private CaixaDeCambio caixaDeCambio;
      private Combustivel combustivel;

       public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao
suspensao, Motor motor, Freio freio, CaixaDeCambio caixaDeCambio,
Combustivel combustivel)
       {
          this.pneuDianteiro = pneuDianteiro;
          this.pneuTraseiro = pneuTraseiro;
          this.suspensao = suspensao;
          this.motor = motor;
          this.freio = freio;
          this.caixaDeCambio = caixaDeCambio;
          this.combustivel = combustivel;
       }
   }
public class Carro
   {
      private Pneus pneuDianteiro;
      private Pneus pneuTraseiro;
      private Suspensao suspensao;
      private Motor motor;
      private Freio freio;
      private CaixaDeCambio caixaDeCambio;
      private Combustivel combustivel;
      private Renavam renavam;

       public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao
suspensao, Motor motor, Freio freio, CaixaDeCambio caixaDeCambio,
Combustivel combustivel, Renavam renavam)
       {
          this.pneuDianteiro = pneuDianteiro;
          this.pneuTraseiro = pneuTraseiro;
          this.suspensao = suspensao;
          this.motor = motor;
          this.freio = freio;
          this.caixaDeCambio = caixaDeCambio;
          this.combustivel = combustivel;
          this.renavam = renavam;
       }
   }
public class Carro
   {
      private Pneus pneuDianteiro;
      private Pneus pneuTraseiro;
      private Suspensao suspensao;
      private Motor motor;
      private Freio freio;
      private CaixaDeCambio caixaDeCambio;
      private Combustivel combustivel;
      private Renavam renavam;

       public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao
suspensao, Motor motor, Freio freio, CaixaDeCambio caixaDeCambio,
Combustivel combustivel, Renavam renavam, ...)
       {
          this.pneuDianteiro = pneuDianteiro;
          this.pneuTraseiro = pneuTraseiro;
          this.suspensao = suspensao;
          this.motor = motor;
          this.freio = freio;
          this.caixaDeCambio = caixaDeCambio;
          this.combustivel = combustivel;
          this.renavam = renavam;
          // ...
       }
   }
Mas quando você
aprende a usar...
Ouça seus testes!
Vou mostrar como
eu vejo o feedback
    dos testes.
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
    {
         // atributos com as dependencias que serao mockadas

        [SetUp]
        public void SetUp() {
            // criando mocks
        }

         [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);
        // alguma outra atividade aqui
        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);
        // some other activity here
        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);
        // alguma outra atividade aqui
        dispatcher.Dispatch(unpacked);
    }
}
mas e o exemplo
   do carro?
public class Carro
    {
        private Pneus pneuDianteiro;
        private Pneus pneuTraseiro;
        private Suspensao suspensao;
        private Motor motor;
        private Freio freio;
        private CaixaDeCambio caixaDeCambio;
        private Combustivel combustivel;

         public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao suspensao,
Motor motor, Freio freio, CaixaDeCambio caixaDeCambio, Combustivel combustivel, ...)
         {
             this.pneuDianteiro = pneuDianteiro;
             this.pneuTraseiro = pneuTraseiro;
             this.suspensao = suspensao;
             this.motor = motor;
             this.freio = freio;
             this.caixaDeCambio = caixaDeCambio;
             this.combustivel = combustivel;
             ...
         }
    }
dependencies,
 notifications,
 adjustments
public class Carro
    {
        private Pneus pneuDianteiro;
        private Pneus pneuTraseiro;
        private Suspensao suspensao;
        private Motor motor;
        private Freio freio;
        private CaixaDeCambio caixaDeCambio;
        private Combustivel combustivel;
        private Renavam renavam;

        public Carro (Renavam renavam)
        {
            this.renavam = renavam;
            this.pneuDianteiro = Pneus.Firestone();
            this.pneuTraseiro = Pneus.Michellin();
            this.suspensao = Suspensao.AMelhor();
            this.motor = Motor.DezesseisValvulas();
            this.freio = Freio.ABS();
            this.caixaDeCambio = CaixaDeCambio.Automatica();
            this.combustivel = Combustivel.Flex();
        }

         public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao suspensao,
Motor motor, Freio freio, CaixaDeCambio caixaDeCambio, Combustivel combustivel, Renavam
renavam)
         {
            // seta os atributos
         }

    }
use um builder!
new CarroBuilder().ComPneu(Pneus.Firestone).ComMotor(Motor.Zetec).[...].Cria();




                                                                       by @cv
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));
        }
    }
Lei de Demeter
  [nada de A.B.metodoC() ...]
Cuidado com herança
 Lembre-se do Princípio de Substituição de Liskov (LSP)
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
                                                      
   {

   {

   
   [SetUp]
                                                      
   
   public GeradorDeNotaFiscal

   
   public void SetUp() {
                                                      (InformacoesFiscais info, Sap sap,

   
   
   sap = new Mock<SAP>();
                                                      EnviadorDeEmail emails)

   
   
   emails = new Mock<EnviadorDeEmail>();
                                                      
   
   {

   
   
   info = new Mock<InformacoesFiscais>();
                                                      
   
   
   // seta atributos

   
   
   gerador = new GeradorDeNotaFiscal(info,
                                                      
   
   }
sap.Object, emails.Object);
                                                      
   

   
   }
                                                      
   
   public NotaFiscal Gera(Fatura fatura) {

   
                                                      
   
   
   var nota = geraNotaUsandoInfo();

   
   [Test] public void DeveEnviarAoSap () {
                                                      
   
   

   
   
   var nf = gerador.gera(fatura);
                                                      
   
   
   sap.EnviaNota(nota);

   
   
   sap.Verify(s => s.EnviaNota(nf),
                                                      
   
   
   emails.EnviaNota(nota);
Times.Once());
                                                      
   
   

   
   }
                                                      
   
   }
                                                      
   }

   
   [Test] public void DeveEnviarOEmail () {

   
   
   var nf = gerador.gera(fatura);

   
   
   emails.Verify(s => s.EnviaNota(nf),
Times.Once());

   
   }}
Single Responsibility
   Principle (SRP)
  (A classe deve ter apenas uma responsabilidade)
public class GeradorDeNotaFiscal

   {

   
 private IList<IObservadorDeNotaGerada> observadores;


   
   public GeradorDeNotaFiscal (InformacoesFiscais info)

   
   {

   
   
 // seta atributos

   
   }


   
   public void AdicionaObservador(IObservadorDeNotaGerada observador) { ... }

   

   
   private void Notifica(NotaFiscal nota) {

   
   
 foreach(var observador in observadores) {
              observador.notifica(nota);
           }

   
   }


   
   public NotaFiscal Gera(Fatura fatura) {

   
   
 var nota = geraNotaUsandoInformacoesFiscais();

   
   

   
   
 Notifica(nota);

   
   }

   }
O teste mostra, mas quem
refatora (para padrões) é você!
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;
                                                  
   
 
 }
                                                  
   
 }
                                                  
   }
Tell, Don’t Ask!
(Você deve dizer ao objeto o que quer que ele faça!)
Cuidado com interfaces que
 interagem somente com o
       mesmo objeto!
    
   public interface BoletoService
    
   {

    
   
   void Emite(Boleto boleto);
    
   
   void Paga(Boleto boleto);
    
   
   void Cancela(Boleto boleto);
            ...
    
   }
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();
    }

    ...
Crie classes especializadas!
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!
          }
     }

    ...
Objetos insubstituíveis
Sintoma: Você precisa mockar um objeto que não é
substituível sem mágica!


   [Test]

   public void DeveEmitirAPassagemComADataAtual() {

   
 var passagem = new GeradorDePassagem().Emite();

   
 Assert.AreEqual(DateTime.Now, passagem.DataEmissao);
    }
Abstração é o segredo!
public class GeradorDePassagem {

   
 public Passagem(IRelogio relogio) { ... }


   
   public Passagem Emite(Passageiro passageiro) {
          var data = relogio.DataAtual;
          // faz alguma coisa com a data...
        }
    }




   [Test]

   public void DeveEmitirAPassagemComADataAtual() {

   
 var agora = DateTime.Now;

   
 relogio.SetupGet(r => r.DataAtual).Returns(agora);


   
   var passagem = new GeradorDePassagem(relogio).Emite();


   
   Assert.AreEqual(agora, passagem.DataEmissao);
    }
Evite singletons!
Nomenclatura ajuda!
Sintoma: O nome da classe e/ou seus métodos não fazem
sentido para o domínio!


   [Test]

   public void DeveFazerAlgumaCoisa() {

   
 var entidade = new GerenciadorServiceImpl(new PassagemDAO()).FazTarefa();
    }
Impl classes are meaningless!
Métodos FazXEY()
If’s e switches
Sintoma: Você tem testes muito parecidos que geram
resultados diferentes, e quando olha a implementação, ela tem
um if ou switch.

   [Test]

   public void CalculaISS() {

   
 var valor = new CalculaImposto().ParaValor(1500);

   
 Assert.AreEqual(1500*1.2, valor);
    }


   [Test]

   public void CalculaICMS() {

   
 var valor = new CalculaImposto().ParaValor(6000);

   
 Assert.AreEqual(6000*1.3, valor);
    }
public class CalculaImposto {

   
 private TipoImposto tipo;


   
   public CalculaImposto(TipoImposto tipo) {
           this.tipo = tipo;
         }


   
   public double ParaValor(double valor) {
           if(valor < 1000) {
             return valor * 1.1;
           }
           else if(valor > 1000 && valor < 5000) {
              return valor * 1.2;
           }
           else if (valor >= 5000 && valor < 8000) {
              return valor * 1.3;
           }
           else { ... }
        }
    }
Elimine if’s e switches na
   medida do possível!
Padrões de projeto podem
    ajudar (de novo)!
Brain classes
Sintoma: Você tem uma classe de teste muito grande.

   [Test]
public   void   DeveFazerX1() { ... }

   [Test]
public   void   DeveFazerX2() { ... }

   [Test]
public   void   DeveFazerX3() { ... }

   [Test]
public   void   DeveFazerX4() { ... }

   [Test]
public   void   DeveFazerX5() { ... }

   [Test]
public   void   DeveFazerX6() { ... }

   [Test]
public   void   DeveFazerX7() { ... }

   [Test]
public   void   DeveFazerX8() { ... }

   [Test]
public   void   DeveFazerX9() { ... }

   [Test]
public   void   DeveFazerX10() { ... }

   [Test]
public   void   DeveFazerX11() { ... }

   [Test]
public   void   DeveFazerX12() { ... }

   [Test]
public   void   DeveFazerX13() { ... }

   [Test]
public   void   DeveFazerX14() { ... }

   [Test]
public   void   DeveFazerX15() { ... }

   [Test]
public   void   DeveFazerX16() { ... }

   [Test]
public   void   DeveFazerX17() { ... }

   [Test]
public   void   DeveFazerX18() { ... }

   [Test]
public   void   DeveFazerX19() { ... }

   [Test]
public   void   DeveFazerX20() { ... }

   [Test]
public   void   DeveFazerXn() { ... }
A mesma coisa se você tem um
cenário muito grande para um
        simples teste!
A mesma coisa se você achar
que precisa testar um método
           privado!
Quebre essa classe em
pequenas outras classes!
       (lembre do SRP novamente!)
Mas é assim que
 eu interpreto!
Você pode achar outras
maneiras de interpretar!
        e se achar, me conta! ;)
"Every pattern describes a problem which occurs over
and over again in our environment, and then describes
the core of the solution to that problem, in such a way
that you can use this solution a million times over,
without ever doing it the same way twice."

Christopher Alexander, "The Pattern Language"
Ouça seus testes!
  deu pra ver o quanto eles têm pra contar?
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!
@mauricioaniche

Mais conteúdo relacionado

Destaque

Patent Pending Linear Bit Counting Implementations
Patent Pending Linear Bit Counting ImplementationsPatent Pending Linear Bit Counting Implementations
Patent Pending Linear Bit Counting ImplementationsMeltin Bell
 
27. Extended Marketing Mix
27. Extended Marketing Mix27. Extended Marketing Mix
27. Extended Marketing MixNBHS
 
Методы стимулирования территориального развития ИКТ отрасли на примере Москвы
Методы стимулирования территориального развития ИКТ отрасли на примере МосквыМетоды стимулирования территориального развития ИКТ отрасли на примере Москвы
Методы стимулирования территориального развития ИКТ отрасли на примере МосквыMichael Kozloff
 
Test Equipment Rental
Test Equipment RentalTest Equipment Rental
Test Equipment Rentalhenharas
 
Forever flowing 3.4
Forever flowing 3.4Forever flowing 3.4
Forever flowing 3.4Geminiasp
 
31. Price
31. Price31. Price
31. PriceNBHS
 
FDI Powerpoint presentation 01 2011
FDI Powerpoint presentation 01 2011FDI Powerpoint presentation 01 2011
FDI Powerpoint presentation 01 2011Dennis Wellman
 
Что такое "Конвергентные ИТ"?
Что такое "Конвергентные ИТ"?Что такое "Конвергентные ИТ"?
Что такое "Конвергентные ИТ"?Michael Kozloff
 
Postnatal Development Of Intestinal Microflora As Influenced By Infant Nutrition
Postnatal Development Of Intestinal Microflora As Influenced By Infant NutritionPostnatal Development Of Intestinal Microflora As Influenced By Infant Nutrition
Postnatal Development Of Intestinal Microflora As Influenced By Infant NutritionBiblioteca Virtual
 
What Do These Pictures Have In Common
What Do These Pictures Have In CommonWhat Do These Pictures Have In Common
What Do These Pictures Have In Commonpatriciapunte
 
«Коломенская пастила», Коломна
«Коломенская пастила», Коломна«Коломенская пастила», Коломна
«Коломенская пастила», КоломнаMichael Kozloff
 

Destaque (20)

Patent Pending Linear Bit Counting Implementations
Patent Pending Linear Bit Counting ImplementationsPatent Pending Linear Bit Counting Implementations
Patent Pending Linear Bit Counting Implementations
 
Doering
DoeringDoering
Doering
 
27. Extended Marketing Mix
27. Extended Marketing Mix27. Extended Marketing Mix
27. Extended Marketing Mix
 
Методы стимулирования территориального развития ИКТ отрасли на примере Москвы
Методы стимулирования территориального развития ИКТ отрасли на примере МосквыМетоды стимулирования территориального развития ИКТ отрасли на примере Москвы
Методы стимулирования территориального развития ИКТ отрасли на примере Москвы
 
AmphorEyes & Lovers' Eyes by Vanessa Somers Vreeland
AmphorEyes & Lovers' Eyes by Vanessa Somers VreelandAmphorEyes & Lovers' Eyes by Vanessa Somers Vreeland
AmphorEyes & Lovers' Eyes by Vanessa Somers Vreeland
 
Test Equipment Rental
Test Equipment RentalTest Equipment Rental
Test Equipment Rental
 
Sokken
SokkenSokken
Sokken
 
Forever flowing 3.4
Forever flowing 3.4Forever flowing 3.4
Forever flowing 3.4
 
31. Price
31. Price31. Price
31. Price
 
Genecode Activity
Genecode ActivityGenecode Activity
Genecode Activity
 
FDI Powerpoint presentation 01 2011
FDI Powerpoint presentation 01 2011FDI Powerpoint presentation 01 2011
FDI Powerpoint presentation 01 2011
 
Что такое "Конвергентные ИТ"?
Что такое "Конвергентные ИТ"?Что такое "Конвергентные ИТ"?
Что такое "Конвергентные ИТ"?
 
Postnatal Development Of Intestinal Microflora As Influenced By Infant Nutrition
Postnatal Development Of Intestinal Microflora As Influenced By Infant NutritionPostnatal Development Of Intestinal Microflora As Influenced By Infant Nutrition
Postnatal Development Of Intestinal Microflora As Influenced By Infant Nutrition
 
Asuka Watercolours Tulips Rose, CHISHOLM GALLERY, LLC
Asuka Watercolours Tulips Rose, CHISHOLM GALLERY, LLCAsuka Watercolours Tulips Rose, CHISHOLM GALLERY, LLC
Asuka Watercolours Tulips Rose, CHISHOLM GALLERY, LLC
 
Ori, febe, shao
Ori, febe, shaoOri, febe, shao
Ori, febe, shao
 
CD+M PPT 2011
CD+M PPT 2011CD+M PPT 2011
CD+M PPT 2011
 
What Do These Pictures Have In Common
What Do These Pictures Have In CommonWhat Do These Pictures Have In Common
What Do These Pictures Have In Common
 
Covers
CoversCovers
Covers
 
Chisholm Gallery, Carolyn Edlund , LANDSCAPES
Chisholm Gallery, Carolyn  Edlund , LANDSCAPESChisholm Gallery, Carolyn  Edlund , LANDSCAPES
Chisholm Gallery, Carolyn Edlund , LANDSCAPES
 
«Коломенская пастила», Коломна
«Коломенская пастила», Коломна«Коломенская пастила», Коломна
«Коломенская пастила», Коломна
 

Semelhante a Test-Driven Development e sua influência no design

Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014
Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014
Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014David Robert Camargo de Campos
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitDiego Tremper
 
Palestra Mocks - AgileBrazil 2010
Palestra Mocks - AgileBrazil 2010Palestra Mocks - AgileBrazil 2010
Palestra Mocks - AgileBrazil 2010rafaelferreira
 
Introdução a programação I
Introdução a programação IIntrodução a programação I
Introdução a programação IClerton Leal
 
Membros da Classe - Preparatório Certificação - OCAJP7 - Aula 2 - D
Membros da Classe - Preparatório Certificação - OCAJP7 - Aula 2 - DMembros da Classe - Preparatório Certificação - OCAJP7 - Aula 2 - D
Membros da Classe - Preparatório Certificação - OCAJP7 - Aula 2 - DPaulo Henrique Lerbach Rodrigues
 
Refatoração de código com Capitão Nascimento versão completa
Refatoração de código com Capitão Nascimento versão completaRefatoração de código com Capitão Nascimento versão completa
Refatoração de código com Capitão Nascimento versão completaEduardo Bregaida
 
Testes de unidade na prática
Testes de unidade na práticaTestes de unidade na prática
Testes de unidade na práticaTiago Furtado
 
Testes Unitários com GTest e Catch
Testes Unitários com GTest e CatchTestes Unitários com GTest e Catch
Testes Unitários com GTest e CatchUilian Ries
 
Respiração Programada
Respiração ProgramadaRespiração Programada
Respiração ProgramadaMarcelo Diniz
 
Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014Michael Castillo Granados
 
Dojo de programação - Dia de Java - UFSCar
Dojo de programação - Dia de Java - UFSCarDojo de programação - Dia de Java - UFSCar
Dojo de programação - Dia de Java - UFSCarLuiz Ribeiro
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitDiego Tremper
 
Curso Java Básico - Aula 03
Curso Java Básico - Aula 03Curso Java Básico - Aula 03
Curso Java Básico - Aula 03Natanael Fonseca
 

Semelhante a Test-Driven Development e sua influência no design (20)

Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014
Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014
Lidando com Java obsoleto: do Struts 1.0 ao CDI - QConSP 2014
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnit
 
Palestra Mocks - AgileBrazil 2010
Palestra Mocks - AgileBrazil 2010Palestra Mocks - AgileBrazil 2010
Palestra Mocks - AgileBrazil 2010
 
Introdução a programação I
Introdução a programação IIntrodução a programação I
Introdução a programação I
 
Clean code
Clean codeClean code
Clean code
 
Membros da Classe - Preparatório Certificação - OCAJP7 - Aula 2 - D
Membros da Classe - Preparatório Certificação - OCAJP7 - Aula 2 - DMembros da Classe - Preparatório Certificação - OCAJP7 - Aula 2 - D
Membros da Classe - Preparatório Certificação - OCAJP7 - Aula 2 - D
 
Refatoração de código com Capitão Nascimento versão completa
Refatoração de código com Capitão Nascimento versão completaRefatoração de código com Capitão Nascimento versão completa
Refatoração de código com Capitão Nascimento versão completa
 
Testes de unidade na prática
Testes de unidade na práticaTestes de unidade na prática
Testes de unidade na prática
 
Testes Unitários com GTest e Catch
Testes Unitários com GTest e CatchTestes Unitários com GTest e Catch
Testes Unitários com GTest e Catch
 
Ganhando tempo com casos de testes
Ganhando tempo com casos de testesGanhando tempo com casos de testes
Ganhando tempo com casos de testes
 
Solid
SolidSolid
Solid
 
Respiração Programada
Respiração ProgramadaRespiração Programada
Respiração Programada
 
Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014
 
Vraptor
VraptorVraptor
Vraptor
 
Programação Orientada por Objectos - Aula 6
Programação Orientada por Objectos - Aula 6Programação Orientada por Objectos - Aula 6
Programação Orientada por Objectos - Aula 6
 
TDD e Clean Code
TDD e Clean CodeTDD e Clean Code
TDD e Clean Code
 
Dojo de programação - Dia de Java - UFSCar
Dojo de programação - Dia de Java - UFSCarDojo de programação - Dia de Java - UFSCar
Dojo de programação - Dia de Java - UFSCar
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnit
 
Curso Java Básico - Aula 03
Curso Java Básico - Aula 03Curso Java Básico - Aula 03
Curso Java Básico - Aula 03
 
Aula5
Aula5Aula5
Aula5
 

Mais de Maurício Aniche

Can ML help software developers? (TEQnation 2022)
Can ML help software developers? (TEQnation 2022)Can ML help software developers? (TEQnation 2022)
Can ML help software developers? (TEQnation 2022)Maurício Aniche
 
Tracing Back Log Data to its Log Statement: From Research to Practice
Tracing Back Log Data to its Log Statement: From Research to PracticeTracing Back Log Data to its Log Statement: From Research to Practice
Tracing Back Log Data to its Log Statement: From Research to PracticeMaurício Aniche
 
Pragmatic software testing education - SIGCSE 2019
Pragmatic software testing education - SIGCSE 2019Pragmatic software testing education - SIGCSE 2019
Pragmatic software testing education - SIGCSE 2019Maurício Aniche
 
Software Testing with Caipirinhas and Stroopwafels
Software Testing with Caipirinhas and StroopwafelsSoftware Testing with Caipirinhas and Stroopwafels
Software Testing with Caipirinhas and StroopwafelsMaurício Aniche
 
Code smells in MVC applications (Dutch Spring meetup)
Code smells in MVC applications (Dutch Spring meetup)Code smells in MVC applications (Dutch Spring meetup)
Code smells in MVC applications (Dutch Spring meetup)Maurício Aniche
 
A Collaborative Approach to Teach Software Architecture - SIGCSE 2017
A Collaborative Approach to Teach Software Architecture - SIGCSE 2017A Collaborative Approach to Teach Software Architecture - SIGCSE 2017
A Collaborative Approach to Teach Software Architecture - SIGCSE 2017Maurício Aniche
 
Code quality in MVC systems - BENEVOL 2016
Code quality in MVC systems - BENEVOL 2016Code quality in MVC systems - BENEVOL 2016
Code quality in MVC systems - BENEVOL 2016Maurício Aniche
 
A Validated Set of Smells for MVC Architectures - ICSME 2016
A Validated Set of Smells for MVC Architectures - ICSME 2016A Validated Set of Smells for MVC Architectures - ICSME 2016
A Validated Set of Smells for MVC Architectures - ICSME 2016Maurício Aniche
 
SATT: Tailoring Code Metric Thresholds for Different Software Architectures (...
SATT: Tailoring Code Metric Thresholds for Different Software Architectures (...SATT: Tailoring Code Metric Thresholds for Different Software Architectures (...
SATT: Tailoring Code Metric Thresholds for Different Software Architectures (...Maurício Aniche
 
DNAD 2015 - Métricas de código, pra que te quero?
DNAD 2015 - Métricas de código, pra que te quero?DNAD 2015 - Métricas de código, pra que te quero?
DNAD 2015 - Métricas de código, pra que te quero?Maurício Aniche
 
Como eu aprendi que testar software é importante?
Como eu aprendi que testar software é importante?Como eu aprendi que testar software é importante?
Como eu aprendi que testar software é importante?Maurício Aniche
 
Proposta: Métricas e Heurísticas para Detecção de Problemas em Aplicações Web
Proposta: Métricas e Heurísticas para Detecção de Problemas em Aplicações WebProposta: Métricas e Heurísticas para Detecção de Problemas em Aplicações Web
Proposta: Métricas e Heurísticas para Detecção de Problemas em Aplicações WebMaurício Aniche
 
Efeitos da Prática de Revisão de Código na Caelum: Um Estudo Preliminar em Du...
Efeitos da Prática de Revisão de Código na Caelum: Um Estudo Preliminar em Du...Efeitos da Prática de Revisão de Código na Caelum: Um Estudo Preliminar em Du...
Efeitos da Prática de Revisão de Código na Caelum: Um Estudo Preliminar em Du...Maurício Aniche
 
Test-Driven Development serve pra mim?
Test-Driven Development serve pra mim?Test-Driven Development serve pra mim?
Test-Driven Development serve pra mim?Maurício Aniche
 
O que estamos temos feito com mineração de repositório de código no IME?
O que estamos temos feito com mineração de repositório de código no IME?O que estamos temos feito com mineração de repositório de código no IME?
O que estamos temos feito com mineração de repositório de código no IME?Maurício Aniche
 
MetricMiner: Supporting Researchers in Mining Software Repositories - SCAM 2013
MetricMiner: Supporting Researchers in Mining Software Repositories - SCAM 2013MetricMiner: Supporting Researchers in Mining Software Repositories - SCAM 2013
MetricMiner: Supporting Researchers in Mining Software Repositories - SCAM 2013Maurício Aniche
 
Does the Act of Refactoring Really Make Code Simpler? A Preliminary Study - W...
Does the Act of Refactoring Really Make Code Simpler? A Preliminary Study - W...Does the Act of Refactoring Really Make Code Simpler? A Preliminary Study - W...
Does the Act of Refactoring Really Make Code Simpler? A Preliminary Study - W...Maurício Aniche
 
Minicurso sobre Evolução de Software no CBSoft 2011
Minicurso sobre Evolução de Software no CBSoft 2011Minicurso sobre Evolução de Software no CBSoft 2011
Minicurso sobre Evolução de Software no CBSoft 2011Maurício Aniche
 
MTD2014 - Are The Methods In Your DAOs in the Right Place? A Preliminary Study
MTD2014 - Are The Methods In Your DAOs in the Right Place? A Preliminary StudyMTD2014 - Are The Methods In Your DAOs in the Right Place? A Preliminary Study
MTD2014 - Are The Methods In Your DAOs in the Right Place? A Preliminary StudyMaurício Aniche
 

Mais de Maurício Aniche (20)

Can ML help software developers? (TEQnation 2022)
Can ML help software developers? (TEQnation 2022)Can ML help software developers? (TEQnation 2022)
Can ML help software developers? (TEQnation 2022)
 
Tracing Back Log Data to its Log Statement: From Research to Practice
Tracing Back Log Data to its Log Statement: From Research to PracticeTracing Back Log Data to its Log Statement: From Research to Practice
Tracing Back Log Data to its Log Statement: From Research to Practice
 
Pragmatic software testing education - SIGCSE 2019
Pragmatic software testing education - SIGCSE 2019Pragmatic software testing education - SIGCSE 2019
Pragmatic software testing education - SIGCSE 2019
 
Test Automation Day 2018
Test Automation Day 2018Test Automation Day 2018
Test Automation Day 2018
 
Software Testing with Caipirinhas and Stroopwafels
Software Testing with Caipirinhas and StroopwafelsSoftware Testing with Caipirinhas and Stroopwafels
Software Testing with Caipirinhas and Stroopwafels
 
Code smells in MVC applications (Dutch Spring meetup)
Code smells in MVC applications (Dutch Spring meetup)Code smells in MVC applications (Dutch Spring meetup)
Code smells in MVC applications (Dutch Spring meetup)
 
A Collaborative Approach to Teach Software Architecture - SIGCSE 2017
A Collaborative Approach to Teach Software Architecture - SIGCSE 2017A Collaborative Approach to Teach Software Architecture - SIGCSE 2017
A Collaborative Approach to Teach Software Architecture - SIGCSE 2017
 
Code quality in MVC systems - BENEVOL 2016
Code quality in MVC systems - BENEVOL 2016Code quality in MVC systems - BENEVOL 2016
Code quality in MVC systems - BENEVOL 2016
 
A Validated Set of Smells for MVC Architectures - ICSME 2016
A Validated Set of Smells for MVC Architectures - ICSME 2016A Validated Set of Smells for MVC Architectures - ICSME 2016
A Validated Set of Smells for MVC Architectures - ICSME 2016
 
SATT: Tailoring Code Metric Thresholds for Different Software Architectures (...
SATT: Tailoring Code Metric Thresholds for Different Software Architectures (...SATT: Tailoring Code Metric Thresholds for Different Software Architectures (...
SATT: Tailoring Code Metric Thresholds for Different Software Architectures (...
 
DNAD 2015 - Métricas de código, pra que te quero?
DNAD 2015 - Métricas de código, pra que te quero?DNAD 2015 - Métricas de código, pra que te quero?
DNAD 2015 - Métricas de código, pra que te quero?
 
Como eu aprendi que testar software é importante?
Como eu aprendi que testar software é importante?Como eu aprendi que testar software é importante?
Como eu aprendi que testar software é importante?
 
Proposta: Métricas e Heurísticas para Detecção de Problemas em Aplicações Web
Proposta: Métricas e Heurísticas para Detecção de Problemas em Aplicações WebProposta: Métricas e Heurísticas para Detecção de Problemas em Aplicações Web
Proposta: Métricas e Heurísticas para Detecção de Problemas em Aplicações Web
 
Efeitos da Prática de Revisão de Código na Caelum: Um Estudo Preliminar em Du...
Efeitos da Prática de Revisão de Código na Caelum: Um Estudo Preliminar em Du...Efeitos da Prática de Revisão de Código na Caelum: Um Estudo Preliminar em Du...
Efeitos da Prática de Revisão de Código na Caelum: Um Estudo Preliminar em Du...
 
Test-Driven Development serve pra mim?
Test-Driven Development serve pra mim?Test-Driven Development serve pra mim?
Test-Driven Development serve pra mim?
 
O que estamos temos feito com mineração de repositório de código no IME?
O que estamos temos feito com mineração de repositório de código no IME?O que estamos temos feito com mineração de repositório de código no IME?
O que estamos temos feito com mineração de repositório de código no IME?
 
MetricMiner: Supporting Researchers in Mining Software Repositories - SCAM 2013
MetricMiner: Supporting Researchers in Mining Software Repositories - SCAM 2013MetricMiner: Supporting Researchers in Mining Software Repositories - SCAM 2013
MetricMiner: Supporting Researchers in Mining Software Repositories - SCAM 2013
 
Does the Act of Refactoring Really Make Code Simpler? A Preliminary Study - W...
Does the Act of Refactoring Really Make Code Simpler? A Preliminary Study - W...Does the Act of Refactoring Really Make Code Simpler? A Preliminary Study - W...
Does the Act of Refactoring Really Make Code Simpler? A Preliminary Study - W...
 
Minicurso sobre Evolução de Software no CBSoft 2011
Minicurso sobre Evolução de Software no CBSoft 2011Minicurso sobre Evolução de Software no CBSoft 2011
Minicurso sobre Evolução de Software no CBSoft 2011
 
MTD2014 - Are The Methods In Your DAOs in the Right Place? A Preliminary Study
MTD2014 - Are The Methods In Your DAOs in the Right Place? A Preliminary StudyMTD2014 - Are The Methods In Your DAOs in the Right Place? A Preliminary Study
MTD2014 - Are The Methods In Your DAOs in the Right Place? A Preliminary Study
 

Test-Driven Development e sua influência no design

  • 1. Test-Driven Development e sua Influência no Design Mauricio Aniche http://www.aniche.com.br
  • 2. Mas o que é TDD mesmo?
  • 3. Red - Green - Refactor
  • 8. 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
  • 9. mas todo mundo já sabe que tdd é sobre design!
  • 10. TDD mostra o problema, mas não resolve pra você!
  • 11. E como ele ajuda?
  • 12. [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?
  • 13. [TestFixture] public class GeradorDeNotaFiscalTest { [Test] public void DeveGerarUmaNotaFiscalEAgruparPorAliquota { var gerador = new GeradorDeNotaFiscal(); var notas = gerador.gera(faturaComServicosComAliquotasDiferentes()); Assert.AreEqual(1, notas.Count); } [Test] public void DeveGerarUmaNotaFiscalEAgruparPorSerie { var gerador = new GeradorDeNotaFiscal(); var notas = gerador.gera(faturaComServicosComSeriesDiferentes()); Assert.AreEqual(1, notas.Count); } } hmm... esse agrupamento é complicado! a implementação tá confusa por causa dele... já sei! vou extrair!
  • 14. [TestFixture] public class GeradorDeNotaFiscalTest { [Test] public void DeveGerarUmaNotaFiscal { var agrupador = new Mock<IAlgoritmoDeAgrupamento>(); var gerador = new GeradorDeNotaFiscal(agrupador.Object); var notas = gerador.gera(fatura); Assert.AreEqual(1, notas.Count); } } nice!
  • 15. mas não é fácil!
  • 17. public class Carro { public Carro () { } }
  • 18. public class Carro { private Pneus pneuDianteiro; public Carro (Pneus pneuDianteiro) { this.pneuDianteiro = pneuDianteiro; } }
  • 19. public class Carro { private Pneus pneuDianteiro; private Pneus pneuTraseiro; public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro) { this.pneuDianteiro = pneuDianteiro; this.pneuTraseiro = pneuTraseiro; } }
  • 20. public class Carro { private Pneus pneuDianteiro; private Pneus pneuTraseiro; private Suspensao suspensao; public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao suspensao) { this.pneuDianteiro = pneuDianteiro; this.pneuTraseiro = pneuTraseiro; this.suspensao = suspensao; } }
  • 21. public class Carro { private Pneus pneuDianteiro; private Pneus pneuTraseiro; private Suspensao suspensao; private Motor motor; public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao suspensao, Motor motor) { this.pneuDianteiro = pneuDianteiro; this.pneuTraseiro = pneuTraseiro; this.suspensao = suspensao; this.motor = motor; } }
  • 22. public class Carro { private Pneus pneuDianteiro; private Pneus pneuTraseiro; private Suspensao suspensao; private Motor motor; private Freio freio; public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao suspensao, Motor motor, Freio freio) { this.pneuDianteiro = pneuDianteiro; this.pneuTraseiro = pneuTraseiro; this.suspensao = suspensao; this.motor = motor; this.freio = freio; } }
  • 23. public class Carro { private Pneus pneuDianteiro; private Pneus pneuTraseiro; private Suspensao suspensao; private Motor motor; private Freio freio; private CaixaDeCambio caixaDeCambio; public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao suspensao, Motor motor, Freio freio, CaixaDeCambio caixaDeCambio) { this.pneuDianteiro = pneuDianteiro; this.pneuTraseiro = pneuTraseiro; this.suspensao = suspensao; this.motor = motor; this.freio = freio; this.caixaDeCambio = caixaDeCambio; } }
  • 24. public class Carro { private Pneus pneuDianteiro; private Pneus pneuTraseiro; private Suspensao suspensao; private Motor motor; private Freio freio; private CaixaDeCambio caixaDeCambio; private Combustivel combustivel; public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao suspensao, Motor motor, Freio freio, CaixaDeCambio caixaDeCambio, Combustivel combustivel) { this.pneuDianteiro = pneuDianteiro; this.pneuTraseiro = pneuTraseiro; this.suspensao = suspensao; this.motor = motor; this.freio = freio; this.caixaDeCambio = caixaDeCambio; this.combustivel = combustivel; } }
  • 25. public class Carro { private Pneus pneuDianteiro; private Pneus pneuTraseiro; private Suspensao suspensao; private Motor motor; private Freio freio; private CaixaDeCambio caixaDeCambio; private Combustivel combustivel; private Renavam renavam; public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao suspensao, Motor motor, Freio freio, CaixaDeCambio caixaDeCambio, Combustivel combustivel, Renavam renavam) { this.pneuDianteiro = pneuDianteiro; this.pneuTraseiro = pneuTraseiro; this.suspensao = suspensao; this.motor = motor; this.freio = freio; this.caixaDeCambio = caixaDeCambio; this.combustivel = combustivel; this.renavam = renavam; } }
  • 26. public class Carro { private Pneus pneuDianteiro; private Pneus pneuTraseiro; private Suspensao suspensao; private Motor motor; private Freio freio; private CaixaDeCambio caixaDeCambio; private Combustivel combustivel; private Renavam renavam; public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao suspensao, Motor motor, Freio freio, CaixaDeCambio caixaDeCambio, Combustivel combustivel, Renavam renavam, ...) { this.pneuDianteiro = pneuDianteiro; this.pneuTraseiro = pneuTraseiro; this.suspensao = suspensao; this.motor = motor; this.freio = freio; this.caixaDeCambio = caixaDeCambio; this.combustivel = combustivel; this.renavam = renavam; // ... } }
  • 29. Vou mostrar como eu vejo o feedback dos testes.
  • 30. 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 { // atributos com as dependencias que serao mockadas [SetUp] public void SetUp() { // criando mocks } [Test] public void ShouldDoSomething() { var processor = new MessageProcessor(unpacker, auditer, locationFinder, counterPartyFinder, domesticNotifier, importedNotifier); processor.OnMessage(BuildSomeSpecificRawMessage()); // algumas assercoes aqui.. } }
  • 31. 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); // alguma outra atividade aqui if (locationFinder.IsDomestic(unpacked)) { domesticNotifier.Notify(unpacked.AsDomesticMessage()); } else { importedNotifier.Notify(unpacked.AsImportedMessage()); } } }
  • 32. 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); // some other activity here if (locationFinder.IsDomestic(unpacked)) { domesticNotifier.Notify(unpacked.AsDomesticMessage()); } else { importedNotifier.Notify(unpacked.AsImportedMessage()); } } }
  • 33. 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); // alguma outra atividade aqui dispatcher.Dispatch(unpacked); } }
  • 34. mas e o exemplo do carro?
  • 35. public class Carro { private Pneus pneuDianteiro; private Pneus pneuTraseiro; private Suspensao suspensao; private Motor motor; private Freio freio; private CaixaDeCambio caixaDeCambio; private Combustivel combustivel; public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao suspensao, Motor motor, Freio freio, CaixaDeCambio caixaDeCambio, Combustivel combustivel, ...) { this.pneuDianteiro = pneuDianteiro; this.pneuTraseiro = pneuTraseiro; this.suspensao = suspensao; this.motor = motor; this.freio = freio; this.caixaDeCambio = caixaDeCambio; this.combustivel = combustivel; ... } }
  • 37. public class Carro { private Pneus pneuDianteiro; private Pneus pneuTraseiro; private Suspensao suspensao; private Motor motor; private Freio freio; private CaixaDeCambio caixaDeCambio; private Combustivel combustivel; private Renavam renavam; public Carro (Renavam renavam) { this.renavam = renavam; this.pneuDianteiro = Pneus.Firestone(); this.pneuTraseiro = Pneus.Michellin(); this.suspensao = Suspensao.AMelhor(); this.motor = Motor.DezesseisValvulas(); this.freio = Freio.ABS(); this.caixaDeCambio = CaixaDeCambio.Automatica(); this.combustivel = Combustivel.Flex(); } public Carro (Pneus pneuDianteiro, Pneus pneuTraseiro, Suspensao suspensao, Motor motor, Freio freio, CaixaDeCambio caixaDeCambio, Combustivel combustivel, Renavam renavam) { // seta os atributos } }
  • 38. use um builder! new CarroBuilder().ComPneu(Pneus.Firestone).ComMotor(Motor.Zetec).[...].Cria(); by @cv
  • 39. 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));         }     }
  • 40. Lei de Demeter [nada de A.B.metodoC() ...]
  • 41. Cuidado com herança Lembre-se do Princípio de Substituição de Liskov (LSP)
  • 42. 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 { { [SetUp] public GeradorDeNotaFiscal public void SetUp() { (InformacoesFiscais info, Sap sap, sap = new Mock<SAP>(); EnviadorDeEmail emails) emails = new Mock<EnviadorDeEmail>(); { info = new Mock<InformacoesFiscais>(); // seta atributos gerador = new GeradorDeNotaFiscal(info, } sap.Object, emails.Object); } public NotaFiscal Gera(Fatura fatura) { var nota = geraNotaUsandoInfo(); [Test] public void DeveEnviarAoSap () { var nf = gerador.gera(fatura); sap.EnviaNota(nota); sap.Verify(s => s.EnviaNota(nf), emails.EnviaNota(nota); Times.Once()); } } } [Test] public void DeveEnviarOEmail () { var nf = gerador.gera(fatura); emails.Verify(s => s.EnviaNota(nf), Times.Once()); }}
  • 43. Single Responsibility Principle (SRP) (A classe deve ter apenas uma responsabilidade)
  • 44. public class GeradorDeNotaFiscal { private IList<IObservadorDeNotaGerada> observadores; public GeradorDeNotaFiscal (InformacoesFiscais info) { // seta atributos } public void AdicionaObservador(IObservadorDeNotaGerada observador) { ... } private void Notifica(NotaFiscal nota) { foreach(var observador in observadores) { observador.notifica(nota); } } public NotaFiscal Gera(Fatura fatura) { var nota = geraNotaUsandoInformacoesFiscais(); Notifica(nota); } }
  • 45. O teste mostra, mas quem refatora (para padrões) é você!
  • 46. 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; } } }
  • 47. Tell, Don’t Ask! (Você deve dizer ao objeto o que quer que ele faça!)
  • 48. Cuidado com interfaces que interagem somente com o mesmo objeto! public interface BoletoService { void Emite(Boleto boleto); void Paga(Boleto boleto); void Cancela(Boleto boleto); ... }
  • 49. 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(); } ...
  • 51. 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! } } ...
  • 52. Objetos insubstituíveis Sintoma: Você precisa mockar um objeto que não é substituível sem mágica! [Test] public void DeveEmitirAPassagemComADataAtual() { var passagem = new GeradorDePassagem().Emite(); Assert.AreEqual(DateTime.Now, passagem.DataEmissao); }
  • 53. Abstração é o segredo!
  • 54. public class GeradorDePassagem { public Passagem(IRelogio relogio) { ... } public Passagem Emite(Passageiro passageiro) { var data = relogio.DataAtual; // faz alguma coisa com a data... } } [Test] public void DeveEmitirAPassagemComADataAtual() { var agora = DateTime.Now; relogio.SetupGet(r => r.DataAtual).Returns(agora); var passagem = new GeradorDePassagem(relogio).Emite(); Assert.AreEqual(agora, passagem.DataEmissao); }
  • 56. Nomenclatura ajuda! Sintoma: O nome da classe e/ou seus métodos não fazem sentido para o domínio! [Test] public void DeveFazerAlgumaCoisa() { var entidade = new GerenciadorServiceImpl(new PassagemDAO()).FazTarefa(); }
  • 57. Impl classes are meaningless!
  • 59. If’s e switches Sintoma: Você tem testes muito parecidos que geram resultados diferentes, e quando olha a implementação, ela tem um if ou switch. [Test] public void CalculaISS() { var valor = new CalculaImposto().ParaValor(1500); Assert.AreEqual(1500*1.2, valor); } [Test] public void CalculaICMS() { var valor = new CalculaImposto().ParaValor(6000); Assert.AreEqual(6000*1.3, valor); }
  • 60. public class CalculaImposto { private TipoImposto tipo; public CalculaImposto(TipoImposto tipo) { this.tipo = tipo; } public double ParaValor(double valor) { if(valor < 1000) { return valor * 1.1; } else if(valor > 1000 && valor < 5000) { return valor * 1.2; } else if (valor >= 5000 && valor < 8000) { return valor * 1.3; } else { ... } } }
  • 61. Elimine if’s e switches na medida do possível!
  • 62. Padrões de projeto podem ajudar (de novo)!
  • 63. Brain classes Sintoma: Você tem uma classe de teste muito grande. [Test] public void DeveFazerX1() { ... } [Test] public void DeveFazerX2() { ... } [Test] public void DeveFazerX3() { ... } [Test] public void DeveFazerX4() { ... } [Test] public void DeveFazerX5() { ... } [Test] public void DeveFazerX6() { ... } [Test] public void DeveFazerX7() { ... } [Test] public void DeveFazerX8() { ... } [Test] public void DeveFazerX9() { ... } [Test] public void DeveFazerX10() { ... } [Test] public void DeveFazerX11() { ... } [Test] public void DeveFazerX12() { ... } [Test] public void DeveFazerX13() { ... } [Test] public void DeveFazerX14() { ... } [Test] public void DeveFazerX15() { ... } [Test] public void DeveFazerX16() { ... } [Test] public void DeveFazerX17() { ... } [Test] public void DeveFazerX18() { ... } [Test] public void DeveFazerX19() { ... } [Test] public void DeveFazerX20() { ... } [Test] public void DeveFazerXn() { ... }
  • 64. A mesma coisa se você tem um cenário muito grande para um simples teste!
  • 65. A mesma coisa se você achar que precisa testar um método privado!
  • 66. Quebre essa classe em pequenas outras classes! (lembre do SRP novamente!)
  • 67. Mas é assim que eu interpreto!
  • 68. Você pode achar outras maneiras de interpretar! e se achar, me conta! ;)
  • 69. "Every pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice." Christopher Alexander, "The Pattern Language"
  • 70. Ouça seus testes! deu pra ver o quanto eles têm pra contar?
  • 71. 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”

Notas do Editor

  1. meu nome eh .. aluno de mestrado, onde pesquiso sobre tdd trablho na locaweb
  2. - Famoso ciclo - Adicione um teste; Rode todos os testes e veja o novo teste falhar; Fa&amp;#xE7;a uma pequena altera&amp;#xE7;&amp;#xE3;o; Rode todos os testes e veja todos passarem; Refatore para remover duplica&amp;#xE7;&amp;#xE3;o.
  3. tem teste no nome...
  4. - Transforma o teste em uma atividade de design, onde os programadores os utilizam para esclarecer as expectativas sobre o que um peda&amp;#xE7;o de c&amp;#xF3;digo deve fazer; mais do que isso, faz vc pensar tamb&amp;#xE9;m no design, e poder mudar de id&amp;#xE9;ia sobre ele (feedback); - Ajuda a resolver um dos maiores problemas do desenvolvimento de software, que &amp;#xE9; o gerenciamento de depend&amp;#xEA;ncias
  5. ter &amp;#x201C;test&amp;#x201D; no nome confunde! muitas defini&amp;#xE7;&amp;#xF5;es que s&amp;#xF3; levam em conta o fato de vc escrever um teste antes (igual a do JUnit in action)
  6. agora todo mundo j&amp;#xE1; sabe... em todo lugar, voc&amp;#xEA; encontra pessoas falando que TDD n&amp;#xE3;o &amp;#xE9; sobre testes e sim sobre design!
  7. - outra coisa que est&amp;#xE1; claro eh que ninguem mais acha q tdd eh a solucao - TDD mostra o problema atraves do feedback dos testes, e a experiencia do programador faz a diferenca para resolver
  8. - sinergia grande entre c&amp;#xF3;digo f&amp;#xE1;cil de testar e bom design - como vimos no exemplo acima, TDD faz com que as depend&amp;#xEA;ncias fiquem naturalmente expl&amp;#xED;citas - al&amp;#xE9;m disso, faz com que os comportamentos sejam invocados de forma mais conveniente.
  9. seus testes provem feedback para vc... vc pensa nas dependencias que essa classe tem, na interface que ela prover&amp;#xE1; para seus clientes e etc...
  10. quando os testes passam a ficar complicados, sempre h&amp;#xE1; uma refatora&amp;#xE7;&amp;#xE3;o para fazer!
  11. novas classes emergem a partir do feedback dos testes! a composicao eh mais simples que a soma das partes
  12. pensar em um design um pouco mais avancado nao eh facil.. como falei, vai da experiencia do programador...
  13. n&amp;#xE3;o &amp;#xE9; t&amp;#xE3;o f&amp;#xE1;cil assim usar o feedback dos testes para guiar o desenvolvimento...
  14. a primeira vez que vc faz TDD, vc &amp;#xE9; meio que obrigado a deixar as dependencias expl&amp;#xED;citas.. e &amp;#xE9; isso que vc faz...
  15. e quando voc&amp;#xEA; v&amp;#xEA; , voc&amp;#xEA; tem uma classe com MUITAS depend&amp;#xEA;ncias, o que faz com que a dificulta a manuten&amp;#xE7;&amp;#xE3;o da mesma.
  16. os testes prov&amp;#xEA;m um feedback imenso sobre o seu design!
  17. n&amp;#xE3;o h&amp;#xE1; muito assunto sobre isso na literatura.. O Freeman tem uma se&amp;#xE7;&amp;#xE3;o no seu livro chamado &amp;#x201C;Listening to the Tests&amp;#x201D;.
  18. God Class: classe com alto acoplamento, que conhece ou faz muito.
  19. veja que a classe CounterPartyFinder &amp;#xE9; usada apenas pela MessageUnpacker... Pq n&amp;#xE3;o passar a depend&amp;#xEA;ncia pra ela?
  20. Agora podemos ver que essa regra de neg&amp;#xF3;cio pode ser encapsulada dentro de outro objeto menor e mais espec&amp;#xED;fico, com um nome que fa&amp;#xE7;a sentido ao dom&amp;#xED;nio...
  21. - Voc&amp;#xEA; pode definir valores padr&amp;#xF5;es e permitir que os mesmos sejam alterados depois. - Receba apenas o que for realmente depend&amp;#xEA;ncia!
  22. veja a API do asp.net mvc! Precisa mockar muita coisa para testar o HttpRequest
  23. ao fazer isso, vc faz com que A de maneira impl&amp;#xED;cita conhe&amp;#xE7;a os detalhes internos de B, aumentando o acoplamento.
  24. Se S &amp;#xE9; um subtipo de T, ent&amp;#xE3;o objetos do tipo T podem ser substitu&amp;#xED;dos por S sem alterar nenhuma propriedade do sistema. - Pr&amp;#xE9;-condi&amp;#xE7;&amp;#xF5;es iguais ou mais fracas e p&amp;#xF3;s-condi&amp;#xE7;&amp;#xF5;es iguais ou mais fortes. Exemplo do quadrado, retangulo
  25. parecem notifiers, n&amp;#xE3;o?
  26. a classe faz mais do que devia! baixa coes&amp;#xE3;o! como comentado anteriormente, esse &amp;#xE9; um bom exemplo de depend&amp;#xEA;ncias do tipo &amp;#x201C;notifiers&amp;#x201D;, e pode ser refatorado!
  27. refatorado para observer... agora quem quiser ser notificado sobre a geracao da nota, torna-se um observer, e ser&amp;#xE1; notificado assim que a nota for gerada... isso desacopla o GeradorDeNotaFiscal do resto do processo, e permite que evolua de maneira mais f&amp;#xE1;cil!
  28. e conhecimento de OO &amp;#xE9; fundamental...
  29. voc&amp;#xEA; deve na medida do poss&amp;#xED;vel optar por pedir ao objeto para fazer, ao inv&amp;#xE9;s de perguntar algo, e a partir da resposta, tomar uma a&amp;#xE7;&amp;#xE3;o. O problema &amp;#xE9; que a classe que faz isso n&amp;#xE3;o deve tomar decis&amp;#xF5;es baseado no estado do outro objeto, violando o encapsulamento.
  30. dados e comportamento devem andar juntos... Muitas vezes abrimos m&amp;#xE3;o disso para flexibilizar (e muitos DP se baseiam nisso). Mas deve-se olhar atentamente!
  31. imagina agora para escrever todos os testes.. era complicado! precis&amp;#xE1;vamos extrair o comportamento para algum lugar... - outro exemplo: criar filtros... se tal campo foi postado, ent&amp;#xE3;o adicione isso na condi&amp;#xE7;&amp;#xE3;o, e por a&amp;#xED; vai...
  32. crie classes especializadas que fa&amp;#xE7;am pequenas partes do todo, cada uma com um comportamento bem espec&amp;#xED;fico. Fa&amp;#xE7;a depois com que seja f&amp;#xE1;cil junt&amp;#xE1;-las para formar um comportamento maior.
  33. a primeira refatoracao eh levar cada filtro para uma classe especifica (depois pode ter uma factory para montar os filtros)... veja que ficou facil customizar o comportamento de um filtro, al&amp;#xE9;m de ser muito mais f&amp;#xE1;cil testar: agora o n&amp;#xFA;mero de combina&amp;#xE7;&amp;#xF5;es para cada um deles &amp;#xE9; muito menor!
  34. o teste vai falhar sempre, pois a data setada vai ser diferente da data comparada, j&amp;#xE1; que a implementa&amp;#xE7;&amp;#xE3;o usa DateTime.Now!
  35. novamente, encontre a melhor abstra&amp;#xE7;&amp;#xE3;o para o seu problema... Encapsule isso em uma classe de dom&amp;#xED;nio. Parece que n&amp;#xE3;o, mas muitos sistemas que lidam com data s&amp;#xE3;o dif&amp;#xED;ceis de testar pois lidam com data diretamente.
  36. agora voc&amp;#xEA; consegue mockar o comportamento da data! alem disso, voc&amp;#xEA; tem uma interface muito mais rica para o seu dom&amp;#xED;nio que trata de datas! Com isso, voc&amp;#xEA; pode adicionar novos comportamentos de maneira f&amp;#xE1;cil!
  37. isso nos mostra que devemos sempre evitar singletons! comportamentos em singletons dificulta os testes dos clientes que usam, al&amp;#xE9;m de criar uma depend&amp;#xEA;ncia forte.
  38. os nomes devem ser claros! se os nomes n&amp;#xE3;o s&amp;#xE3;o claros o bastante, pode indicar que a abstra&amp;#xE7;&amp;#xE3;o n&amp;#xE3;o foi bem pensada!
  39. classes que tem o sufixo Impl indicam um problema de design. Geralmente isso acontece pq a classe tem apenas uma &amp;#xFA;nica implementa&amp;#xE7;&amp;#xE3;o! Por exemplo, se vc tiver a interface Cliente, e a classe ClienteImpl, muito provavelmente vc tem um problema na abstra&amp;#xE7;&amp;#xE3;o!
  40. m&amp;#xE9;todos com &amp;#x201C;E&amp;#x201D; no nome j&amp;#xE1; indicam que o m&amp;#xE9;todo faz duas coisas!
  41. repare que a diferen&amp;#xE7;a &amp;#xE9; apenas o tipo do imposto
  42. - eles apenas aumentam a complexidade ciclom&amp;#xE1;tica do c&amp;#xF3;digo - pode se tornar gigante, e a manuten&amp;#xE7;&amp;#xE3;o pode ser complicada
  43. strategy, state ajudam a reduzir essa complexidade!
  44. idealmente n&amp;#xE3;o se tem muito para testar em uma classe... ela deve ter apenas uma responsabilidade! se isso acontecer, voc&amp;#xEA; muito provavelmente est&amp;#xE1; testando uma brain class!
  45. pode indicar que essa classe tambem toma muita decisao sozinha!
  46. se vc acha q precisa testar um m&amp;#xE9;todo privado, &amp;#xE9; pq essa classe est&amp;#xE1; fazendo coisa demais! :)
  47. o livro do feathers d&amp;#xE1; algumas sugest&amp;#xF5;es de como fazer essa refatora&amp;#xE7;&amp;#xE3;o!