Começando com este conceito:
1) Comece com o comportamento que você deseja. Faça um teste para isso. Veja falha no teste.
2) Escreva código suficiente para passar no teste. Veja todos os testes aprovados.
3) Procure por código redundante / desleixado -> refatorar. Veja os testes ainda passam. Goto 1
Então, no 1, digamos que você deseja criar um novo comando (estou estendendo a maneira como o comando funcionaria, então tenha paciência comigo). (Além disso, vou ser um pouco pragmático, em vez de extremo TDD)
O novo comando é chamado MakeMyLunch, então você primeiro cria um teste para instancia-lo e obtém o nome do comando:
@Test
public void instantiateMakeMyLunch() {
ICommand command = new MakeMyLunchCommand();
assertEquals("makeMyLunch",command.getCommandName());
}
Isso falha, forçando você a criar a nova classe de comando e a retornar seu nome (o purista diria que são duas rodadas de TDD, não 1). Então você cria a classe e ela implementa a interface ICommand, incluindo o retorno do nome do comando. A execução de todos os testes agora mostra todas as aprovações, portanto, você procura oportunidades de refatoração. Provavelmente nenhum.
Então, em seguida, você deseja que ele execute execute. Então você tem que perguntar: como sei que "MakeMyLunch" com sucesso "preparou meu almoço". O que muda no sistema devido a esta operação? Posso testar isso?
Suponha que seja fácil testar:
@Test
public void checkThatMakeMyLunchIsSuccessful() {
ICommand command = new MakeMyLunchCommand();
command.execute();
assertTrue( Lunch.isReady() );
}
Outras vezes, isso é mais difícil, e o que você realmente deseja fazer é testar as responsabilidades do sujeito em teste (MakeMyLunchCommand). Talvez a responsabilidade do MakeMyLunchCommand seja interagir com o Fridge and Microwave. Então, para testá-lo, você pode usar um refrigerador e um micro-ondas simulados. [dois exemplos de estruturas simuladas são Mockito e nMock ou veja aqui .]
Nesse caso, você faria algo como o seguinte pseudo-código:
@Test
public void checkThatMakeMyLunchIsSuccessful() {
Fridge mockFridge = mock(Fridge);
Microwave mockMicrowave = mock(Microwave);
ICommand command = new MakeMyLunchCommand( mockFridge, mockMicrowave );
command.execute();
mockFramework.assertCalled( mockFridge.removeFood );
mockFramework.assertCalled( microwave.turnon );
}
O purista diz que teste a responsabilidade de sua classe - suas interações com outras classes (o comando abriu a geladeira e ligou o microondas?).
O pragmatista diz teste para um grupo de classes e teste para o resultado (o seu almoço está pronto?).
Encontre o equilíbrio certo que funciona para o seu sistema.
(Nota: considere que talvez você tenha chegado à sua estrutura de interface muito cedo. Talvez você possa deixar isso evoluir à medida que você escreve seus testes de unidade e implementações, e na etapa 3 você "percebe" a oportunidade de interface comum).