(この日本語訳は 2016/10/16 時点の https://github.com/nodejs/node/blob/v6.x/doc/guides/writing_tests.md の翻訳です。)
テストは、Nodeによって提供される特定の機能を実行し、期待通りの挙動をすることをチェックするNodeスクリプトでなければ なりません。テストが成功したら 0 を返し、失敗するなら fail させなければなりません。テストは、次のような場合に fail します。
code != 0
でprocess.exit(code)
を呼び出して exit する。- uncaught exception で exit する。
- exit しない。この場合、最大制限時間を設定しているので test runner がテストを終了します。
幾つかの理由でテストを追加します。
- 新規機能を追加する時
- regressionやバグを修正する時
- テストカバレッジを広げる時
Node.jsのテストスィートから以下の基本的なテストを解説しましょう。
1 'use strict';
2 const common = require('../common');
3 const http = require('http');
4 const assert = require('assert');
5
6 const server = http.createServer(common.mustCall((req, res) => {
7 res.end('ok');
8 }));
9 server.listen(0, () => {
10 http.get({
11 port: server.address().port,
12 headers: {'Test': 'Tokyo'}
13 }, common.mustCall((res) => {
14 assert.equal(res.statusCode, 200);
15 server.close();
16 }));
17 });
1-2行目
'use strict';
const common = require('../common');
これらの2つの行は必須です。全てのテストに含まれないといけません。
common
モジュールは、テストのための便利なツールを提供するヘルパーモジュールです。
もし何らかの理由で common
の機能を使わなくても、このように include すべきです。
require('../common');
なぜ? global のリークをチェックするためです。
3-4行目
const http = require('http');
const assert = require('assert');
これらのモジュールは、テストを実行するために必要なものです。特別な場合を除いて、コアモジュールだけを include すべきです。
assert
モジュールはテストの前提が合致しているのをチェックするもので、ほとんどのテストで使われます。
6-17行目
この部分はテスト本体です。このテストは非常に簡単なもので、HTTPサーバがリクエストを受け取る時にヘッダに non-ASCIIキ ャラクターを受け入れることをテストするだけのものです。注目すべき面白い点は、
- もしテストが特定のポート番号に依存していないなら、任意の値を使うより 0 を常に使いましょう。なぜならOSがランダムポートを割り当てるので安全にテストを並行稼動させることができるからです。例えばテストが特定のポートに期待通りに割り当 てられていることをチェックするテストが必要なら、特定のポート番号を割り当てるのはOKです。
common.mustCall
は、あるコールバックやリスナーが呼ばれたことをチェックするために使います。- HTTPサーバは全てのチェックが実行されたら一度クローズします。この方法で、テストは gracefully に exit できます。テ ストが成功したら status code 0 で exit しなければならないことを忘れてはいけません。
タイマー自身のテスト以外でタイマーの利用は推奨されていません。これには様々な理由があります。 主に flakiness の原因となるからです。詳しくは、ここの説明をお読みく ださい。
タイマーが必要なイベントでは、プラットフォームに依存した特定のタイムアウトを指定できる common.platformTimeout()
メソッドを使うことが推奨されます。例えば、
const timer = setTimeout(fail, common.platformTimeout(4000));
は、4秒タイムアウトを生成しますが、他のプラットフォームではある係数をかけた遅延になるでしょう。
common
モジュールのヘルパーをできるだけ利用しましょう。
common.mustCall
が重要です。common.mustCall
を利用すると、特別な変数やそれに対応した assertion を避けることができるでしょう。テストスイートからの実際のテストで説明しましょう。
'use strict';
var common = require('../common');
var assert = require('assert');
var http = require('http');
var request = 0;
var response = 0;
process.on('exit', function() {
assert.equal(request, 1, 'http server "request" callback was not called');
assert.equal(response, 1, 'http request "response" callback was not called');
});
var server = http.createServer(function(req, res) {
request++;
res.end();
}).listen(0, function() {
var options = {
agent: null,
port: this.address().port
};
http.get(options, function(res) {
response++;
res.resume();
server.close();
});
});
common.mustCall
を使うことによってこのテストは次のように非常に簡略化することができるでしょう。
'use strict';
var common = require('../common');
var assert = require('assert');
var http = require('http');
var server = http.createServer(common.mustCall(function(req, res) {
res.end();
})).listen(0, function() {
var options = {
agent: null,
port: this.address().port
};
http.get(options, common.mustCall(function(res) {
res.resume();
server.close();
}));
});
いくつかのテストは特定のコマンドラインフラグをセットして Node.jsを実行することが必要でしょう。
これを行うには、 // Flags:
コメントをテストの前文に加えてテストをその後に続けます。
例えば internal/*
モジュールが必要なテストを行えるようにするには、--expose-internals
フラグが必要です。
internal/freelist
を必要とするテストは、このように始めます。
'use strict';
// Flags: --expose-internals
require('../common');
const assert = require('assert');
const freelist = require('internal/freelist');