メモログ

Jasmineでのテストで、requireJSのmoduleに対してspyOnしたい

jasmine でのテストで、requireJS の module に対して spyOn したい場合、どうしたら良いのかなという話。module を呼び出す側の処理で、module に適切な値をちゃんと渡しているかを確認したいときが、ある。普通はないかもしれないけど。とにかく、そういうときに spyOn してその値を確認したい。

たとえば下記のようなモジュールの場合。foo.js というファイル名でモジュール名は「foo」となるとして。

define(function(){
  return function(arg1,arg2){
    // do sutekina something
  }
});

上記のモジュールを Dependency として扱う下記のようなモジュールがあるとする。モジュール名は「bar」となるとして。

define([foo],function(Foo){
  return function(){
    var foo = new Foo('hoge','fuga');
  }
});

それで、bar のモジュールのテストで、foo にきちんと値がわたっているかを確認したいとする。

it('a small world',function(){
  var flag;
  var stubModule = {
    stub: function (arg1, arg2) {
      // write some code to work tests well
      flag = true;
    }
  };

  define('foo', [], function(){
    return stubModule.stub;
  });

  spyOn(stubModule, 'stub').andCallThrough();

  require(['bar'], function (Bar) {
    new Bar();
  });

  waitsFor(function () {
    return flag;
  }, 'timeout error on require foo or bar', 3000);

  runs(function () {
    var args = stubModule.stub.mostRecentCall.args;
    expect(args[0]).toEqual('hoge');
    expect(args[1]).toEqual('fuga');
  });
});

spyOn は spyOn(object, methodName)という形で、第一引数で object を渡して、第二引数で object の中のメソッド名を指定するという風に使うので、stubModule はオブジェクトとして用意する。 そして、define で foo モジュールを定義して、stubModule.stub を返すようにする。

それで stubModule の stub を spyOn(stubModule,‘stub’)で spyOn すると。

すでに module が require されている場合は、require.undef(‘foo’)でundefiningして、$(‘script[src$=“foo.js”]‘).remove();とかして、require されていないのと同様の状態に戻さないとだめかもしれない(そしてテスト後に、stub を require.undef して require し直す)。

というメモ… 内容は[Unit testing JavaScript modules using RequireJS and Jasmine | iterativo](http://iterativo.wordpress.com/2012/03/06/unit-testing-javascript- modules-using-requirejs-and-jasmine/)の記事を参考にしました。TDD で開発しているとこうした Testability 的に good でない状況に陥らないのかどうなのか。もっと良いやり方あるかなあ。

私について

Yutaka Yamaguchi
東京在住。TypeScript, Node.js, Reactなどフロンエンドが主力。Perlも書く。SwiftやRubyも過去には使ってた。過去のTOEIC 860くらい。