Skip to content

Latest commit

 

History

History
254 lines (213 loc) · 10.1 KB

writing_tests_ja.md

File metadata and controls

254 lines (213 loc) · 10.1 KB

Node.js プロジェクトにおけるテストの書き方

(この日本語訳は 2016/10/16 時点の https://github.com/nodejs/node/blob/v6.x/doc/guides/writing_tests.md の翻訳です。)

テストとは?

テストは、Nodeによって提供される特定の機能を実行し、期待通りの挙動をすることをチェックするNodeスクリプトでなければ なりません。テストが成功したら 0 を返し、失敗するなら fail させなければなりません。テストは、次のような場合に fail します。

  • code != 0process.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 API

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');