SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

C#で始めるテスト駆動開発入門

TDDBC大阪の課題をC#でやってみる ~ クラス設計とTDD

C#で始めるテスト駆動開発入門(5)

  • X ポスト
  • このエントリーをはてなブックマークに追加

ステップ5 釣り銭と売り上げ管理

 お題の最後のステップは、次のようになっています。

ステップ5 釣り銭と売り上げ管理


  1. ジュース値段以上の投入金額が投入されている条件下で購入操作を行うと、釣り銭(投入金額とジュース値段の差分)を出力する。
    • ジュースと投入金額が同じ場合、つまり、釣り銭0円の場合も、釣り銭0円と出力する。
    • 釣り銭の硬貨の種類は考慮しなくてよい。

 各パーツはだいたいできあがってきたので、ここでは自動販売機クラスに組み立てましょう。なお、題意を少し変えて、購入後に返却操作をしたときにお釣りが返ってくるものとします。

自動販売機クラスの設計

 ここまで各バーツの設計を進めてきて、自動販売機クラスが備えるべき機能や状態はだいたい分かってきました。まとめると次の表のようになるでしょう。

自動販売機クラスが公開すべき状態と機能
利用者 種類 シグネチャ
サービスマン 状態 int Get在庫数(ジュース)
int 売り上げ金額
機能 void 在庫を追加する(ジュース, int)
お客 状態 int 預り金
IEnumerable<ジュース> 購入品トレイ
int 釣り銭トレイ
機能 void お金を投入する(int)
void 購入する(ジュース)
void 返金してもらう()

自動販売機クラスを作る

 最初は、クラスを作ってみるテストです。Get在庫数()も一緒に実装してしまいましょう

テストコード: コンストラクターのテスト
[TestCase]
public void ConstructorTest() { 
  // 初期状態でコーラ5本を在庫している
  var vendingMachine = new 自動販売機();
  Assert.AreEqual(5, vendingMachine.Get在庫数(ジュース.コーラ));
}
製品コード: 自動販売機クラス
public class 自動販売機 {

  internal 商品ラック _rack;

  public 自動販売機() {
    this._rack = new 商品ラック();
  }

  public int Get在庫数(ジュース kind) {
    return _rack.Get在庫数(kind);
  }
}

自動販売機クラスを完成させる

 自動販売機クラスは、各パーツに処理を委譲してしまいますので、実装らしい実装はほとんどありません。そこで、前述のメソッドやプロパティをひととおり使用するシナリオを1つ書いて、残りを一気に実装してしまいましょう。

テストコード: シナリオテスト
[TestCase]
public void シナリオTest() { 
  // 在庫を追加
  var vm = new 自動販売機();
  vm.在庫を追加する(ジュース.レッドブル, 5);
  vm.在庫を追加する(ジュース.水, 5);

  // 購入
  Assert.AreEqual(0, vm.預り金);
  CollectionAssert.IsEmpty(vm.購入品トレイ);
  Assert.AreEqual(0, vm.釣り銭トレイ);

  vm.お金を投入する(100);
  vm.お金を投入する(100);
  vm.お金を投入する(10);
  vm.お金を投入する(10);
  vm.お金を投入する(10);
  vm.お金を投入する(1);
  vm.お金を投入する(5);
  Assert.AreEqual(230, vm.預り金);
  Assert.AreEqual(6, vm.釣り銭トレイ);

  vm.購入する(ジュース.コーラ);
  Assert.AreEqual(110, vm.預り金);
  CollectionAssert.AreEqual(
    new List<ジュース>() { ジュース.コーラ, }, 
    vm.購入品トレイ
  );
  Assert.AreEqual(6, vm.釣り銭トレイ);

  vm.購入する(ジュース.レッドブル);  //残金110円では買えない
  Assert.AreEqual(110, vm.預り金);
  CollectionAssert.AreEqual(
    new List<ジュース>() { ジュース.コーラ, }, 
    vm.購入品トレイ
  );
  Assert.AreEqual(6, vm.釣り銭トレイ);

  vm.購入する(ジュース.水);
  Assert.AreEqual(10, vm.預り金);
  CollectionAssert.AreEqual(
    new List<ジュース>() { ジュース.コーラ, ジュース.水 }, 
    vm.購入品トレイ
  );
  Assert.AreEqual(6, vm.釣り銭トレイ);

  vm.返金してもらう();
  Assert.AreEqual(0, vm.預り金);
  CollectionAssert.AreEqual(
    new List<ジュース>() { ジュース.コーラ, ジュース.水 }, 
    vm.購入品トレイ
  );
  Assert.AreEqual(16, vm.釣り銭トレイ);

  // 販売後の状態
  Assert.AreEqual(4, vm.Get在庫数(ジュース.コーラ));
  Assert.AreEqual(5, vm.Get在庫数(ジュース.レッドブル));
  Assert.AreEqual(4, vm.Get在庫数(ジュース.水));
  Assert.AreEqual(220, vm.売り上げ金額);
}
製品コード: 自動販売機クラス
public class 自動販売機 {

  public IList<ジュース> 購入品トレイ { get; private set; }

  public int 釣り銭トレイ { get; private set; }

  public int 預り金 { get { return _coinMech.預り金; } }

  public int 売り上げ金額 { get { return _coinMech.売り上げ金額; } }


  private コインメック _coinMech;
  private 商品ラック _rack;
  private コントローラー _controller;

  public 自動販売機() {
    this._rack = new 商品ラック();
    this._coinMech = new コインメック();
    this._controller = new コントローラー(_coinMech, _rack);
    this.購入品トレイ = new List<ジュース>();
  }


  public int Get在庫数(ジュース kind) {
    return _rack.Get在庫数(kind);
  }

  public void 在庫を追加する(ジュース kind, int number) {
    _rack.在庫を追加する(kind, number);
  }


  public void お金を投入する(int coin) {
    釣り銭トレイ += _coinMech.お金を投入する(coin);
  }

  public void 購入する(ジュース kind) {
    ジュース commodity = _controller.購入する(kind);
    if( !(commodity == null)) {
      購入品トレイ.Add(commodity);
    }
    // ここで、預り金と最安商品価格とを比較して、返金してもらう()を呼び出すこともできる。
  }

  public void 返金してもらう() {
    釣り銭トレイ += _coinMech.お金を払い戻す();
  }
}

次のページ
クラス設計とTDD

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
C#で始めるテスト駆動開発入門連載記事一覧

もっと読む

この記事の著者

biac(ばいあっく)

HONDA R&Dで自動車の設計をやっていた機械屋さんが、技術の進化スピードに魅かれてプログラマーに。以来30年ほど、より良いコードをどうやったら作れるか、模索の人生。わんくま同盟の勉強会(名古屋)で、よく喋ってたりする。2014/10~2019/6 Microsoft MVP (Windows Devel...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/6633 2012/06/29 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング