この概念から始めます
。1)希望する動作から始めます。そのためのテストを書きます。テスト失敗を参照してください。
2)テストに合格するのに十分なコードを記述します。すべてのテストに合格することを確認します。
3)冗長な/ずさんなコードを探す->リファクタリング。テストがまだ成功することを確認してください。後藤1
したがって、#1で、新しいコマンドを作成したいとしましょう(コマンドの機能を拡張しているので、我慢してください)。(また、私は極端なTDDではなく少し実用的です)
新しいコマンドはMakeMyLunchと呼ばれるため、最初にそれをインスタンス化するためのテストを作成し、コマンド名を取得します。
@Test
public void instantiateMakeMyLunch() {
ICommand command = new MakeMyLunchCommand();
assertEquals("makeMyLunch",command.getCommandName());
}
これは失敗し、新しいコマンドクラスを作成して、その名前を返すように強制します(純粋に言うと、これはTDDの1ラウンドではなく2ラウンドです)。したがって、クラスを作成し、コマンド名を返すなど、ICommandインターフェイスを実装するようにします。すべてのテストを実行すると、すべてのパスが表示されるので、リファクタリングの機会を探すために進みます。おそらくない。
したがって、次に実行を実装する必要があります。「MakeMyLunch」が「ランチを作った」ことをどのようにして知ることができるでしょうか。この操作により、システムはどのように変化しますか?これをテストできますか?
次のことをテストするのが簡単だとします。
@Test
public void checkThatMakeMyLunchIsSuccessful() {
ICommand command = new MakeMyLunchCommand();
command.execute();
assertTrue( Lunch.isReady() );
}
他の場合には、これはより難しく、あなたが本当にやりたいことは、テスト対象(MakeMyLunchCommand)の責任をテストすることです。おそらく、MakeMyLunchCommandの責任は、冷蔵庫と電子レンジを操作することです。したがって、それをテストするには、模擬冷蔵庫と模擬電子レンジを使用できます。[2つのサンプルモックフレームワークはMockitoとnMock です。または、こちらをご覧ください。]
その場合は、次の疑似コードのようにします。
@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 );
}
純粋主義者は、クラスの責任をテストします-他のクラスとの相互作用(コマンドが冷蔵庫を開いて電子レンジをオンにしましたか?)。
実用主義者は、クラスのグループのテストと結果のテスト(ランチの準備はできていますか?)と言います。
システムに適したバランスを見つけてください。
(注意:インターフェイス構造にたどり着いたのが早すぎると考えてください。ユニットテストと実装を作成するときに、おそらくこれを進化させて、ステップ3で共通のインターフェイスの機会を「通知」することができます)。