Quando usar Mocks e Stubs?

Bom dia Pessoal.

Continuando os estudos sobre TDD e BDD, estes dias me venho a questão:
- Quando usar Mocks/Stubs?
- Quando não usar?

Então pensei, isso é uma boa questão, pois se você exagerar no uso deles seus testes podem se tornar fakes, desnecessários e/ou confusos.

O que são Mocks

Segundo Martin Flower, são instancias de objetos reais, mas treinados para dar retornos esperados. Para utiliza-los você precisa de um framework, por exemplo no Java temos o Mockito, EasyMock entre outros.

Exemplo:

   @Test
   public void testGivenNewBehaviorForToStringWhenCastItShouldReturnNewReturn()
   {
      // given
      String resultExpected = "New Return";
      MyObject instance = Mockito.mock(MyObject.class);
      Mockito.when(instance.toString()).thenReturn(resultExpected);
      
      // when
      String result = instance.toString()
      
      // then
      assertEquals(resultExpected, result);
    }

O que são Stubs

Segundo Martin Flower, são implementações de interfaces com retorno esperados para testes de integração.

Veja o exemplo, vamos supor que temos a seguinte interface:

  public interface IJob {
    public String getResult();
  }

E uma classe usando ela:

class Worker {
  private IJob job;
  
  public void setJob(IJob job)
  {
     this.job = job;
  }

  public String work()
  {
     return job.getResult();
  } 
}

Seu teste usando Stub seria assim:

 class WorkerTest extend TestCase {
     @Test
     public void testGivenNewJobWhenWorkItShouldReturnJobDone()
     {
         // given
         String resultExpected = "Job done.";
         Worker worker = new Worker();
         worker.setJob(new StubJob());

         // when
         String result = worker.work();         

         // then
         assertEquals(resultExpected, result);
     }

     class StubJob implements IJob {
         @override 
         public String getResult()
         {
            return "Job done.";
         }
     }
 }

Quando devo usar?

Teste Unitário , como o proprio nome diz, é o teste da classe/funcionalidade/comportamento esperado. Se para testar isso, você tem que se preocupar muito com dependências, acesso a banco, webservice, configurações e isto irá influênciar no resultado, talvez a saída seja o uso de mocks/stubs para emular estes retornos e testar só as funcionalidades da classe que possui estas dependências.

Quando usar um e quando usar outro?

Segundo Dave Sayer em seu artigo para spring.io (Artigo em Inglês):

Seu teste deve ser fácil de ler e manter, então utilize a ferramenta que mais se adapte a estas duas necessidades. Caso o teste começe a ficar complexo dificultando o entendimento do que está sendo testado, talves seja o momento de repensar ele.

Abraços