AMD準拠のmochaテストをWebとCUIで共通化
2013年7月15日
define([
"module-name"
], function(
moduleName
){
descrive("A title", function(){
it("A test", function(){
});
});
};
以下の環境で使い回すためにやったことのまとめです。
- RequireJS を介して読み込み、Web ブラウザから実行する
- node.js の mocha コマンドから実行する
問題点: mocha コマンドから RequireJS を使うと不具合
問題になったのは、CUI から、つまり mocha コマンドから読み込んだ場合です。
まず、RequireJS は Node.js からの使用もサポートしており、
基本的には、AMD 準拠で定義しても困ることはありません。
例えば、以下のコードを node から動かした場合は、正常に動きます。
use_requirejs.js:
var define = requirejs = require("requirejs");
requirejs.config({
baseUrl: __dirname,
nodeRequire: require
});
define([
"some-module"
], function(
someModule
){
console.log("OK");
});
実行結果:
$ node use_requirejs.js OK
しかしながら、以下の mocha テストケースを mocha コマンドから実行すると、
テストが全く実行されません。
mocha_test.js:
var define = requirejs = require("requirejs");
requirejs.config({
baseUrl: __dirname,
nodeRequire: require
});
define([
"expect.js"
], function(
expect
){
describe("Did it run?", function(){
it("expect is function", function(){
expect(expect).to.be.a("function");
});
});
});
実行結果:
$ mocha mocha_test.js 0 passing (1 ms) // 期待していたのは 1 passing
原因と解決策その1
解決策のその1としては、テストをこのように書き直すと正常に動くようになります。
mocha_test_2.js:
var define = requirejs = require("requirejs");
requirejs.config({
baseUrl: __dirname,
nodeRequire: require
});
describe("Did it run?", function(){
it("expect is a function", function(){
// テスト内でモジュールを読み込む
define([
"expect.js"
], function(
expect
) {
expect(expect).to.be.a("function");
});
});
});
実行結果:
$ mocha mocha_test_2.js ․ 1 passing (6 ms)
Answer 2: Change RequireJS to amdefine!
そこでもう一つの方法としては、
node 用の AMD ローダーとしては、RequireJS は止めて、
amdefine という別のローダーを使うことです。
mocha_test_3.js:
// Don't forget "(module)"!
var define = require("amdefine")(module);
define([
"expect.js"
], function(
expect
) {
describe("Did it run?", function(){
it("expect is a function", function(){
expect(expect).to.be.a("function");
});
});
});
実行結果:
mocha mocha_test_3.js ․ 1 passing (6 ms)
しかも何と、この amdefine は、RequireJS と同じ作者さんのものです!
安心感あるあるー!
テストランナーを作る必要がある
自分のプロジェクトでは、このようなテストランナーを作って、
mocha コマンドから実行させています。
mochaから呼ぶのはこれだけにしている:
$ mocha runner.js
RequireJS 側の paths 設定と同期するためにひと処理入れたり、
expect.js や sinon などを、グローバル領域に展開したりしています。
この辺のノウハウをお持ちの方が居ましたら、
是非参考リポジトリを教えていただけると有り難いです。
蛇足: 何故 node から実行したいの?
自分がCUIの方が慣れているから、という理由です。
例えば、Web側のテストランナーとして使っている Testem ですが、
CI 用の出力モードを持っており、CUIのテストとして使えないこともありません。
しかし、実行が遅い、console.log が出力されない、などの不便な点が多く、
メインのテスト実行方法として使うには適していませんでした。
今回、RequireJS を使いつつ以下のテスト方法が揃ったので、
- mocha コマンドからバシバシ CUI でテスト
- たまに testem ci で、ブラウザでもエラーになってないかをテスト
- 表示やアニメが絡むものは testem + ブラウザを実操作でテスト
状況により使い分けることで、開発がやりやすくなったと思います!