[IM]JavaScriptのメソッド内関数だけをテストする

INTER-Mediatorだけの話ではなく、JavaScript一般的な話です。メソッドの中に、そのメソッドの中だけで使う関数を書くということが可能なので、INTER-Mediatorではそういう実装をあちらこちらでやっています。処理の多いメソッドでは関数に分離することで見通しが良くなりますが、加えて、メソッド内の関数レベルでのテストをするということも考えました。

以下のプログラムで、変数anObjectはあるオブジェクトを参照しています。オブジェクトはmethod1というメソッドがあり、そのメソッドの中で、内部の関数であるfunc1を呼び出しています。このプログラムにより、コンソールには、”method1″ “func1″と2行の出力が行われます。

var anObject = {
  prop1: null,
  method1: function() {
    console.log("method1");
    func1();
    // method1のその他の処理
    function func1() {
      console.log("func1");
    }
  }
}

anObject.method1();

ここで、func1だけをテスト対象にしたく、かつmethod1の実処理を行いたくないと考えたとします。その場合、次のようにプログラムを変更しました。このプログラムは、こちらのページの記載を参考にしました。

var bObject = {
  prop1: null,
  method1: function(isTesting) {
    console.log("method1: isTesting="+isTesting);
    this.func1 = function() {
      console.log("func1");
    };
    if(isTesting) {
      return;
    }
    this.func1();
    // method1のその他の処理
  }
}

bObject.method1();
(new bObject.method1(true)).func1();

ポイントは、内部関数func1をプロパティにしていることです。そして、テストか通常利用かを示す引数isTestingを追加します。この引数は省略すると、undefinedになりますので、テスト時はtrueを追加するとして、省略時は何も指定しないことにします。テストの時には、プロパティへ内部関数の設定だけを行い、メソッドはそのまま終了します。

最後からの2行目は、普通にmethod2を利用する場合を想定しており、コンソールには、”method1: isTesting=undefined” “func1″と出力されます。この記述は、最初のプログラムの最後の行にある「anObject.method1();」と全く同じで、method1はつまりは通常利用では何も変更せずにそのまま利用できます。

一方、一番最後の行の実行により、コンソールには”method1: isTesting=true” “func1″と表示されます。newがあることでmethod1をコンストラクタとして実行するので、メソッド自体を返し、その結果、func1関数がメソッドのように実行できます。コンソールに”func1″と表示するのは、method1内部のthis.func1()を実行している部分ではありません。isTesting編集がtrueなので、その前にmethod1は終了します。つまり、「(new bObject.method1(true)).func1();」という記述で、func1だけを実行できるので、この関数だけの単体テストができるということです。

ちなみに、この方法は、method1に引数があっても利用できます。