ドメインモデルの実装(4) ~PlaceOrderServiceTest~
前回モック用に作ったインターフェースを利用して、PlaceOrderServiceのテストコードを書きます。
@RunWith(JMock.class) public class PlaceOrderServiceTests extends TestCase { private PendingOrderRepository pendingOrderRepository; private PendingOrder pendingOrder; private String pendingOredrId; private Date goodDeliveryTime; private Address goodDeliveryAddress; private PlaceOrderService service; private Mockery context = new JUnit4Mockery(); public void setUp() throws Exception { pendingOrderRepository = context.mock(PendingOrderRepository.class); service = new PlaceOrderServiceImpl(pendingOrderRepository); pendingOrder = context.mock(PendingOrder.class); goodDeliveryAddress = new Address(); goodDeliveryTime = new Date(); pendingOredrId = "pendingOrderId"; } @Test public void testUpdateDeliveryInfo_Good() { context.checking(new Expectations() {{ allowing(pendingOrderRepository).findOrCreatePendingOrder(pendingOredrId); will(returnValue(pendingOrder)); }}); context.checking(new Expectations() {{ allowing(pendingOrder).updateDeliveryInfo(goodDeliveryAddress,goodDeliveryTime); will(returnValue(true)); }}); PlaceOrderServiceResult result = service.updateDeliveryInfo(pendingOredrId, goodDeliveryAddress, goodDeliveryTime); PendingOrder pendingOrder = result.getPendingOrder(); assertTrue(result.isSuccess()); PendingOrder returnPendingOrder = result.getPendingOrder(); assertSame(pendingOrder, returnPendingOrder); assertEquals(goodDeliveryAddress, pendingOrder.getDeliveryAddress()); assertEquals(goodDeliveryTime, pendingOrder.getDeliveryTime()); } }
ドメインモデルの実装(3) ~implementing the method~
テストケースに対するアプリ側のコードを実装します。
public class PlaceOrderServiceImpl implements PlaceOrderService { private PendingOrderRepository pendingOrderRepository; public PlaceOrderService(PendingOederRepository repository) { this.pendingOrderRepository = repository; } public PlaceOrderServiceResult updateDeliveryInfo( String pendingOrderId, Addres deliveryAddress, Date deliveryTime) { PendingOeder pendingOrder = pendingOrderRepository.findOrCreatePendingOrder(pendingOederId); boolean success = pendingOrder.updateDeliveryInfo(deliveryAddress, deliveryTime); return new PlaceOedreServiceResult(success, pendingOrder) } }
PlaceOrderServiceは、PendingOrderRepositoryとPendingOrderClassとコラボレートします。
しかしこの時点では、まだ深入りしたくないので、モックを使用します。
jMockを使用するにあたり、PendingOrderRepositoryとPendingOrderの各インターフェース必要とします。
PendingOrderRepositoryは、findOrderCreatePendingOrder()を定義します。
public interface PendingOrderRepository { PendingOrder findOrCreatePendingOrder(String pendingOrderId); }
PendingOrderのupdateDeliveryInfo()は、とりあえずfalseを返します。
public interface PendingOrder { public boolean updateDeliveryInfo(Address deliveryAddress, Date deliveryTime) ; }
ドメインモデルの実装(2) ~The valid delivery Information test case~
updateDeliveryInfo()が呼ばれるとき、PlaceOrderServiceはPendingOrderを読み出すか、存在しなければ生成する。
まずは、大枠として以下のシナリオを想定する。
1) 入力されたデリバリ時刻が未来日時で、デリバリ情報に該当する少なくとも1つのレストランがある場合、PalceOrderServiceはPendingOrderを新しいデリバリ情報で更新する。
そして、成功ステータスコードとPendingOrderを含むPlaceOrderServiceResultを返す。
2) 入力されたデリバリ時刻が未来日時ではなく、または、デリバリ情報に該当する少なくとも1つのレストランがない場合、PalceOrderServiceはPendingOrderを更新しない。
そして、失敗ステータスコードとPendingOrderを含むPlaceOrderServiceResultを返す。
まずは、1)のシナリオのテストケースを記述するとこんな感じ。
# makeGoodDeliveryAddress()、makeGoodDeliveryTime()は別定義。
public class PlaceOrderServiceTests { private PlaceOrderService service; public void setUp() throws Exception { service = new PalaceOrderServiceImpl(); } @Test public void testUpdateDeliveryInfo_Valid() { Address deliveryAddress = makeGoodDeliveryAddress(); Date deliveryTime = makeGoodDeliveryTime(); String pendingOrderId = null; PlaceOrderServiceResult result = service.updateDeliveryInfo(pendingOrderId, deliveryAddress, deliveryTime); PendingOrder pendingOrder = result.getPendingOrder(); assertTrue(result.isSuccess()); assertEquals(deliveryAddress, pendingOrder.getDeliveryAddress()); assertEquals(deliveryTime, pendingOrder.getDeliveryTime()); } }
ドメインモデルの実装(1)
最初にメソッドupdateDeliveryInfo()を実装します。
その後、updateDeliveryInfo()の中で呼ばれるPendingOrderのメソッドを実装します。
また、必要とされるリポジトリも識別し実装します。
まずは、サービスのメソッドを実装。
public interface PlaceOrderService { PlaceOrderServiceResult updateDeliveryInfo(String pendingOrderId, Address deliveryAddress, Date deliveryTime); }
引数はPendingOrderId、deliveryAddress、deliveryTimeの3つ。
PendingOrderIdはDB上のPendingOrderの主キー。HttpSessionやブラウザのプレゼン層で保持される
deliveryAddressとdeliveryTimeは、ユーザによって入力されるデリバリ情報を示す。
開発環境
これから実装を行っていくにあたり、環境を記しておきます。
使用するライブラリは順次追加していくつもりです。
JDK: Java SE 6 update31
Tomcat:Tomcat 6.0.35
開発ツール:Spring Tool Suite(STS) 3.0.0
Maven Dependenciesライブラリ:
No. | GroupID | Artifact ID | Version | Scope | 説明 |
---|---|---|---|---|---|
1 | org.springframework | spring-context | 3.1.1.RELEASE | compile | Spring Context |
2 | org.springframework | spring-webmvc | 3.1.1.RELEASE | compile | Spring MVC |
3 |
システムシーケンス図の作成
前回、システムイベントメッセージを抽出しましたので、それをもとにシステムシーケンス図を作成します。
システムシーケンス図については、書籍「実践UML」が参考になります。
とりあえず、最初のメッセージにだけ、引数を入れてみます。
システムイベントメッセージの抽出
ユースケースから、お客のリクエスト(システムイベントメッセージ)を抽出します。そのシステムイベントメッセージ毎にメソッド名をつけます。
No. | システムイベントメッセージ | 説明 | メソッド |
---|---|---|---|
1 | Enter delivery Info | お客がデリバリー情報を入力する。 | UpadateDeriveryInfo |
2 | Select restaurant | お客がレストランを選択する。 | updateRestaurant |
3 | Update quantities | お客がメニューとその数を入力する。 | updateQuantities |
4 | Check out | お客が入力したメニューと数が正しいことを確認する。 | checkout |
5 | Entry payment information | お客が支払い(クレジットカード)情報 を入力する。 | updatePaymentInformation |
6 | Place Order | お客が注文した内容を確認する。 | placeOrder |
次回、これをもとにシステムシーケンス図を作成します。