assert.CallTracker と must-call

この記事はリクルートエンジニアアドベントカレンダーの2日目の記事です。過ぎてるかもしれませんが、メンバーから脅迫されて書いてます。

f:id:yosuke_furukawa:20201204210950p:plain

assert.CallTracker

Node.js で experimental な API として assert.CallTracker がv14 で追加されました。 この機能は呼び出された回数を検証するという機能を持った新しい assert 関数です。

コールバック関数をテストする際に使える便利関数です。機能としては地味ですが、使いこなせると便利なので紹介します。

const assert = require('assert');

const tracker = new assert.CallTracker();

function func() {}

// 一度だけ呼ばれることを期待
const callsfunc = tracker.calls(func, 1);

// ここで呼び出す。
callsfunc();

// tracker.verify を呼ぶことで何度呼ばれたかを検証する。
// これはプログラムが終わるときに1度だけ呼ばれてることを検証する。
process.on('exit', () => {
  tracker.verify();
});

これだけ見ていると何が便利かわからないかも知れませんが、テストを書いた時にコード内の不具合で assert が呼ばれずに終わってしまう状況を防ぐことができます。

const assert = require('assert');
const tracker = new assert.CallTracker();

const http = require('http');

const server = http.createServer();
// 一回だけリクエストが来ることを期待
server.on("request", tracker.calls((req, res) => {
  assert.strictEqual("/", req.url);
  res.end("Hello World!");
}, 1));

server.listen(3000);

process.on("SIGINT", () => {
  // もしも一度もリクエストが来なかったらここで検証失敗が出る
  tracker.verify();
  process.exit();
});

とまぁ、ここまでが CodeGrid で書いた内容です。

www.codegrid.net

ここから蛇足と言うか多少細かすぎて伝わらない話をしようかと。

mustCall

この機能もともとどこから来たかと言うと、 Node.js のコアのテストでよく書かれてた common.mustCall っていう test utility 関数から来ています。

https://github.com/nodejs/node/tree/master/test/common#mustcallfn-exact

これを一般向けに公開したのがこの機能です。 Node.js の中では Event を使ったテストが多く、『イベントが呼ばれなかった時に検証が行われずそのままパスしてしまう』というのを防ぐモチベーションで作られていました。

今では実は jest とかでもやっちゃうときはやっちゃいますよね。

余談ですが、この機能はめっちゃ便利だなーと思っていたので昔 must-call っていうライブラリとして公開していました。

www.npmjs.com

f:id:yosuke_furukawa:20201204215906p:plain

今となっては assert.CallTracker で置き換えるか、 npm モジュールにしなくても数行で書けると思うので、役目を終えたライブラリになりました。

他にも test common な utility にある便利な関数はあると思うので、意外とこの辺りは公開すると便利かもしれませんね。

https://github.com/nodejs/node/tree/master/test/common

急遽書いたので内容薄いですが、もう少し濃いやつはまた次回。