SHOEISHA iD

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

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

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

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

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

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

ステップ1 扱えないお金

 これもコインメックだけの機能です。お題はこうなっています。

ステップ1 扱えないお金


  1. 想定外のもの(硬貨:1円玉、5円玉。お札:千円札以外のお札)が投入された場合は、投入金額に加算せず、それをそのまま釣り銭としてユーザに出力する。

ステップ1 0: 受け入れ可能な金種

 このステップを進むためには、想定内のモノとは何かという定義が必要です。扱えるお金は何かがハッキリすれば、扱えないお金も判別できるというわけです。「○○、△△、□□以外の場合は、××する」という場合、まず「○○、△△、□□」をまとめて識別できるようになっているか(なっていなければそこから作る)、と考えるのがセオリーです。

 メンバー変数にint型の配列として受け入れ可能な金種を定義し、Is受け入れ可能な金種()メソッドを実装します。テストケースを順番にRED→GREENにしていきますが、以下には最後の状態だけを示します。

テストコード: 受け入れ可能な金種かどうか判定する
[TestCase(1, false)]    // 製品コードは return false; だけの仮実装
[TestCase(10, true)]    // int配列を定義し、10だけをセット。メソッドはここで完成。
[TestCase(50, true)]    // int配列に50を追記。以下、100,500,1000で繰り返す。
[TestCase(100, true)]
[TestCase(500, true)]
[TestCase(1000, true)]
public void Is受け入れ可能な金種Test(int 金種, bool 期待値) {
  Assert.AreEqual(期待値, コインメック.Is受け入れ可能な金種(金種));
}
製品コード: コインメッククラス
private static readonly int[] 受け入れ可能な金種
  = new int[] { 10, 50, 100, 500, 1000, };

internal static bool Is受け入れ可能な金種(int 金種) {
  return 受け入れ可能な金種.Contains(金種);
}

ステップ1 1: 受け入れられない金種は返却する

 これでこのステップをクリアする準備はできました。ところで、「釣り銭としてユーザに出力する」というのはどういうことでしょう?とりあえず、お金を投入する()メソッドの戻り値を返却金額としておきましょう。

 このテストケースには、預り金は変化しないというアサートを入れないと、製品コードのif文が書けません。

テストコード: 受け入れられない金種は返却する
public void 扱えないお金を投入するTest() {
  コインメック cm = new コインメック();
  var 払戻金 = cm.お金を投入する(5);

  Assert.AreEqual(5, 払戻金);
  Assert.AreEqual(0, cm.預り金);
}
製品コード: コインメッククラス
public int お金を投入する(int coin) {  //void→intに変えた
//TODO: 戻り値が返金だというのは、分かりにくい!
  if(Is受け入れ可能な金種(coin)){
    預り金 += coin;
    return 0;
  }
  return coin;
}

コインメックのクラス図

 ここまでで、コインメッククラスは次の図のようになりました。

コインメックのクラス図(ステップ1終了時点)
コインメックのクラス図(ステップ1終了時点)

 状態として預り金を持っています。状態を変更するメソッドが1つと、状態に関係しないメソッドが1つ。十分にシンプルなクラスで、責務も投入されたお金を預かることだけです。よって、これ以上の分割を考える必要はまだ無いでしょう。この先は少なくとも、預り金を減らす方向のメソッドが追加されることになるでしょう。

ステップ2 ジュースの管理

 このステップでは、商品ラックを作ることになります。お題は次のようになっています。

ステップ2 ジュースの管理


  1. 値段と名前の属性からなるジュースを1種類格納できる。初期状態で、コーラ(値段:120円、名前"コーラ")を5本格納している。
  2. 格納されているジュースの情報(値段と名前と在庫)を取得できる。

ステップ2 0: 「コーラ」を識別する

 商品ラックには「コーラ」を格納するということですから、まずその「コーラ」を用意しなければなりません。「コーラ」の1缶1缶を識別する必要はなさそうですから、商品の種類としての「コーラ」が表現できればよさそうです。自販機が扱う商品全般をジュースクラスとし、「コーラ」はジュースクラスの1インスタンスとすればよいでしょう。

 ジュースクラスのインスタンスは、名前Nameと値段Priceだけを固定で持っていればよいです。在庫の数は、ジュースクラスのインスタンス(商品の種類)が知っている必要はなく、商品ラックが分かっていれば良い事です。

 コーラインスタンスの取得と、それがNamePriceプロパティを持っていることを、1つのテストケースで書いてしまいましょう。この程度であれば、まとめてやってしまっても、混乱したり間違えたりすることはないでしょう。

テストコード: ジュースクラスからコーラインスタンスを得る
[TestCase]
public void コーラTest() {
  ジュース cola = ジュース.コーラ;

  Assert.AreEqual("コーラ", cola.Name);
  Assert.AreEqual(120, cola.Price);
}
製品コード: ジュースクラス
public class ジュース {

  public string Name { get; private set; }
  public int Price { get; private set; }

  private ジュース() { 
    // (void)
  }

  public static ジュース コーラ {
    get { 
      return new ジュース(){ Name = "コーラ", Price = 120, };
    }
  }
}

ステップ2 1,2: 商品ラックにコーラを格納する

 コーラの在庫を商品ラックに直接持たせてもよいのですが、後で複数種類のジュースを扱うことになる事は分かりきっているので、ビンも用意してしまいましょう。商品ラックはビンを持っており、ビンにジュースを格納するという形にします。

 このステップ2の1(初期状態でコーラ5本を格納している)と2(格納されているジュースの情報を取得する)は、まとめてテストケースを書きます。

テストコード: 商品ラックビンには初期状態でコーラが5本格納されている
[TestCase]
public void ConstructorTest_初期状態でコーラが5本() {
  商品ラック rack = new 商品ラック();

  Assert.AreEqual(5, rack.ビン.在庫数);
  Assert.AreEqual("コーラ", rack.ビン.商品.Name);

  // すぐに「ビン」は複数になるはずだが、とりあえずこれで。
}
製品コード: ビンクラスと商品ラッククラス
internal class ビン {
  public ジュース 商品 { get; internal set; }
  public int 在庫数 { get; internal set; }
}

internal class 商品ラック {

  public ビン ビン{ get; private set; }

  public 商品ラック() {
    ビン = new ビン() { 商品 = ジュース.コーラ, 在庫数 = 5, };
  }
}

次のページ
ステップ3 購入

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

  • 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」など、さまざまなカンファレンスを企画・運営しています。

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

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

メールバックナンバー

アクセスランキング

アクセスランキング