計画と改善

エンジニアのブログ

フローチャート作成、実装、テストまでの実践

この一冊でわかるソフトウェアテストの教科書を読んでいてロジックの整理やテストケースの作成が苦手だと感じたので、フローチャートやテストケースを作成する練習をしてみた。 書籍ではポイント計算プログラムの仕様は以下の通りだった。

  • レディースデー
    • 火曜日、女性は3割引
  • ポイント2倍
    • 月曜日は購入金額に関わらず2倍
    • 曜日に関わらず5000円以上購入するとポイント2倍

そのままフローチャートを作ると以下になる(書籍同様)

曜日=月曜と料金≥5000の条件が同じポイント2倍なので、料金≥5000がポイント3倍になったケースはどうなるか考えてみた。

シンプルな例だけどいざ自分で書こうとすると意外と時間がかかる。こうして図に示すことができると業務フローの整理には良い。

続いてjavaで上記のフローチャートをコードを作ってみた。週、性別、料金、ポイント、割引の初期値は適当。

class Main {
  public static void main(String[] args) {
    String week = "Monday";
    String sex = "Female";
    double price = 3000;
    double point = 100;
    double discount = 1;

    if (week.equals("Tuesday") && sex.equals("Female")) {
      discount = 0.7;
    }
    if (price >= 5000) {
      point *= 3;
    } else if (week.equals("Monday")) {
      point *= 2;
    }
    System.out.println("price: " + price * discount); // price: 3000.0
    System.out.println("point: " + point); // point: 200
  }
}

この初期値の場合、割引なし、ポイント2倍となりロジック的には正しい。

が、コードに直してみると違和感がでてきた。特にpriceの部分で年齢が60歳以上の時に、pointが4倍になるというロジックが追加された時に以下のようなコードを書いてしまう恐れがある。

if (price >= 5000) {
  point *= 3;
} else if (week.equals("Monday")) {
  point *= 2;
} else if (age >= 60) {
  point *= 4;
}

この場合、price = 6000かつage = 65などの場合などにpointが4倍になることを期待していても、point3倍になってしまう。

class Main {
  public static void main(String[] args) {
    String week = "Monday";
    String sex = "Female";
    double price = 6000;
    double point = 100;
    double discount = 1;
    int age = 65;

    if (week.equals("Tuesday") && sex.equals("Female")) {
      discount = 0.7;
    }
    if (price >= 5000) {
      point *= 3;
    } else if (week.equals("Monday")) {
      point *= 2;
    } else if (age >= 60) {
      point *= 4;
    }
    System.out.println("price: " + price * discount); // price: 6000.0
    System.out.println("point: " + point); // point: 300.0(ポイント400.0を期待)
  }
}

このようなロジックをテストで落としたいのはもちろんだが、コーディング段階で落とせるならそれに越したことはない。

対策として、getMaxPointTimesという関数を作成し、ポイント倍率の最大値を求める関数を切り出してみた。

この関数でも相変わらずpoint *= 4;を愚直に関数の最後に追加すると誤ったロジックとなってしまうが、MaxPointTimesという命名にしておけば、ポイントの最大値を求めるという意図をコード上で示すことはできる。

class Main {
  public static void main(String[] args) {
    String week = "Monday";
    String sex = "Female";
    double price = 6000;
    double point = 100;
    double discount = 1;
    int age = 65;

    if (week.equals("Tuesday") && sex.equals("Female")) {
      discount = 0.7;
    }
    point = getPoint(price, point, week, age);
    System.out.println("price: " + price * discount); // price: 6000.0
    System.out.println("point: " + point); // point: 400.0
  }

  public static double getPoint(double price, double point, String week, int age) {
    double pointTimes = getMaxPointTimes(price, week, age);
    return point * pointTimes;
  }

  public static double getMaxPointTimes(double price, String week, int age) {
    double pointTimes = 1;
    if (age >= 60) {
      pointTimes = 4;
    } else if (price >= 5000) {
      pointTimes = 3;
    } else if (week.equals("Monday")) {
      pointTimes = 2;
    }
    return pointTimes;
  }
}

もっと良いやり方があればご指摘いただけると幸いです。

また表にするまでもないと思ったが、一応現在までのフローチャートも添付しておく。

さらにこれらの条件を樹形図にすると全部で8通りあることがわかる。

レディースデーとポイントの分岐をそれぞれテーブルで表すと以下のようになる。 レディースデーの分岐では以下の4通り。

ポイントの分岐は以下の4通り。

上記の情報をもとに条件を網羅するテストケースを作成する。

レディースデー分岐に関しては条件が2つあるので、複合条件網羅するようにテストケースを作成する。

複合条件網羅とは?

プログラム中の条件分岐に複数の条件の組み合わせがある場合に、そのすべての組み合わせを網羅することを複合条件網羅という。

条件網羅では個々の条件について真と偽の両方が含まれていれば別の条件との組み合わせは関知しないが、複合条件網羅では条件の真偽のすべての組み合わせをテストする必要がある。if(A or B) という2つの条件を組み合わせた分岐の場合、(A,B)=(真,真)(偽,偽)(真,偽)(偽,真)の4ケースが必要となる。

参考:条件網羅(C2 / コンディションカバレッジ)とは - 意味をわかりやすく - IT用語辞典 e-Words

ポイント分岐に関しては年齢、料金、曜日の分岐の条件がそれぞれ1つのためそれぞれの分岐が最低一度通るようにテストケースを作成するとする。

色々な値が取れるが、最低でも4テストケースは必要になる。サンプルとしては以下のような値を入れれば条件を網羅できる。 先ほど作成しておいたJavaのコードでテストを行う。point = 100を初期値として固定して、それぞれの値をテストケースの通りに入力してテストしてみる。以下は出力結果。

  1. price: 2800.0, point: 100.0
  2. price: 4000.0, point: 400.0
  3. price: 8000.0, point: 300.0
  4. price: 4000.0, point: 200.0

最後に

実はこのテストの過程でファイルにスペルミスがあり、期待通りにならなかったところ、今回のテストで発見できたので改めてテストの重要性を認識することができた。

またこのようなシンプルなケースでも結構時間がかかってしまった。テストに関してはコードの綺麗な書き方やアルゴリズム的な考え方も身につくので、時間はかかるが得るものも多い。