代表的なコマンドを1つ選んで、端から端まで実行されていることを確認します。あるいは、実行されたという通知を返す以外は何もしない、次のようなダミーコマンドを実装するという方法もあります。
public class NullCommand implements Command { public static boolean wasExecuted = false; public void execute() { wasExecuted = true; } }
この変更を加えた後、さらにCommandFactoryに手を加え、CommandFactoryがnullを絶対に返さず、代わりにNullCommandオブジェクトを返すようにしました(リスト11を参照)。
public class CommandFactoryTest { private Request request; @Before public void initialize() { request = new Request(); } @Test public void createValidCommands() { assertCommandType("return", ReturnCommand.class); assertCommandType("addPatron", AddPatronCommand.class); } @Test public void createWithNoCommandParameter() { assertEquals(NullCommand.class, CommandFactory.create(request).getClass()); } @Test public void createWithBadCommandParameter() { assertCommandType("badComment", NullCommand.class); } @Test public void createDummy() { assertCommandType("dummy", NullCommand.class); } private void assertCommandType(String commandArgument, Class commandClass) { request.setParameter("command", commandArgument); assertEquals(commandClass, CommandFactory.create(request) .getClass()); } }
対応するCommandFactoryの実装をリスト12に示します。
public class CommandFactory { public static Command create(Request request) { String command = request.getParameter("command"); if (command != null) { if (command.equals("return")) return new ReturnCommand(request); if (command.equals("addPatron")) return new AddPatronCommand(request); } return new NullCommand(); } }
このように変更したことで、CommandFactoryがnullを返すことはあり得なくなりました。serviceのテストは非常に簡単です。
@Test public void service() { NullCommand.wasExecuted = false; LibrarySystem system = new LibrarySystem(); Request request = new Request(); request.setParameter("command", "dummy"); system.service(request); assertTrue(NullCommand.wasExecuted); }
お気づきのとおり、この方法ではNullCommandクラスを使うようになりました。これによって不都合が生じることはありません。あったとしても、テスト可能な範囲が広がったメリットを考えれば安いものです。
より優れたデザインを目指して少しずつリファクタリングすることはどのコードでも可能です。この記事の改良後のコードは、Commandパターンという非常に便利で広く知られたソフトウェアデザインパターンに従っています。今回の場合、テストのニーズを追及したら、優れたデザインコンセプトがついてきたということですね。
