Headline About TechLog Download Java VBA Link


January 19, 2008. Saturday.

JUnitでテストファースト(1) - 仕様を元にテストを作る

前回はJUnitの取りあえずの使い方を説明しました。読んでいただいた方は、何となく使い方を掴んでいただいたと思います。今回は実際にJUnitでTest Firstを実現し、従来のウォーターフォーモデルではなく、スパイラルモデルでプロジェクトを行う手順を説明します。今回も前回同様Eclipse上でサンプルの作成・実行を行いますが、取り上げる内容は開発環境にかかわらず、共通の物になるとはずです。




要件定義

まずは開発するプログラムの要件を定義します。今回はサンプルとして「挨拶ロボット」を作成します。まずは会議室でホワイトボードなどに挨拶ロボットの機能を箇条書きします。


・ロボットには名前が設定できる。

・ロボットには製造年月日が設定される。


動作イメージはこんな感じです。といっても、実際にはただのキャラクタベースのプログラムのクラスですから、ロボットの姿は脳内で保管してくださいね。





設計

では要求の決まったところで、仕様を決めて設計を行いましょう。使い勝手の良いロボットクラスを想像します。こんな感じの仕様を考えてみました。


・ロボットは何体でも作る事が出来る。

・製造年月日は作成時にしか指定できない。

・名前はいつでも変更できる。


ロボットは大量生産したいし、名前は製造後にいつでも変えられるようにしたいですね。一方、製造年月日は製造のタイミングでつけるべきだし、勝手に変えられては困ります。

ではjavaのインターフェイスに置き換えてみましょう。


package net.sdls.barista.tech.robot;

public interface GreetingRobot {
  GreetingRobot(int year, int month, int date);
  void setName(String newName);
  public String getMessage();
}

こんな感じでしょうか。製造や名前の変更は知らない人には出来ないようにしたいので、package privateにしました。一方挨拶は誰とでも出来た方がよいのでpublicとしています。また、製造日の改竄には厳しいご時世なので、製造後に変更が出来ないよう、コンストラクタの引数で設定するようにしています。




テストの作成

さて設計が終わったところでGreetingRobotクラスの実装に取りかかり...たい所ですが、ぐっと堪えて先にテストクラスの実装を行います。先ほど設計したGreetingRobotクラスが実装済みである前提で次のようにGreetingRobotTestクラスを作って見ましょう。


package net.sdls.barista.tech.robot;
import junit.framework.TestCase;

public class GreetingRobotTest extends TestCase {

  /**
   * 作成後名前を「データ」とし、挨拶を取得するテスト
   * "こんにちは。私の名前はデータです。"
   * という文字列をリターンする事を確認
   */
  public void testGetMessage() {
    GreetingRobot robot = new GreetingRobot(2007, 10, 23);
    robot.setName("データ");
    String message = robot.getMessage();

    if (!"こんにちは。私の名前はデータです。".equals(message)) {
      fail(answer + " != " + message);
    }
  }
}

テストを作成する上で気をつけておきたいポイントがいくつかあります。まず、TestCaseクラスを継承すること、それから、テストメソッド名をtestXXXX()という命名にすることです。これは古いJUnitでは必須となります。なお、新しいバージョンのJUnitではこれらの制限はありません。バージョンによる違いについてはまた、別の章で取り上げたいと思います。

次に気をつけて欲しいのが、必ずテストされるクラスと同じパッケージに作ることです。テストクラスはテスト対象のクラスメソッドを呼び出すため、別パッケージに作成すると、publicメソッドしか試験できません。同じパッケージに配置すればpackage privateなメソッド、変数までは試験が可能です。では、protectedや、privateのメソッド・変数はどうするのかというと....それについてもまた別の章で取り上げたいと思います。

「同じパッケージにテストを作成すると、テストコードと納品物が混在するのが嫌だ」と言う方が多いのですが、それについては、コンパイル用のAnt等の設定などで回避が可能です。Antを書くのが面倒、あるいは書き方がわからない、という方はソースフォルダを分けるという手段でも解決が可能です。右のようにEclipse上でソースフォルダを2つに分ける、或いはbatなどでコンパイルする際に2つのフォルダをソースフォルダとして指定しておけば簡単です。私は前者(Eclipseでソースフォルダを2つ)を愛用しています。




テストの実行

では次にテストを実行します。「いや、何も実装してないし」と言いたくなるでしょうが、それでも実行します。前回と同様右クリックメニューからJUnitを実行すると「必要なプロジェクトにエラーがあります。:xxxx(プロジェクト名)。起動しますか?」というダイアログが表示されます。気にせず[先行]ボタンを押してみましょう。

結果はどうだったでしょうか?右の図のように「コンパイル問題が解決できません」とエラーになったのではないかと思います。「ほら見ろ、無駄なことを!」と怒られる声が聞こえそうですね。ですが、これがストリクトなテストファースト・プロジェクトの手順なのです。プログラマはまず仕様に沿って試験を書き、続いて試験が通ることを目標にコーディングを行います。必ず試験を先に作成するのです。




さて、本文が随分長くなってきたので、今回はここまでします。次回はテストに合わせ実際のコードの実装を行っていきます。テストファーストの良さがわかり始めるのはもう少し後となるので、今回の記事で「面倒くせぇ」と投げてしまわず、読み進んでくださいね。 (と書いた以上、早く続きを書いてuploadしなくては...)



Next: JUnitでテストファースト(2) - テストに合わせ実装を行う >>