別にしんどくないブログ

技術のことや読書メモを書いています

Denoの標準テストモジュールについて。READMEをコミットした

あけましておめでとうございます。今年もよろしくお願いいたします。

2018年末からDenoのコードを読んだり、Denoについて調べたりしています。
DenoのテストモジュールのREADMEを書いてマージされました。今年最初のマージされたPRになります。

github.com

せっかくなので、Denoの標準テストモジュールについて簡単に紹介したいと思います。

Denoとは

Node.jsを最初に作ったRyan Dahl氏が開発しているTypeScriptをV8で動かすラインタイム実行環境です。

deno_stdとは

Denoにはいくつか標準モジュールが用意されています。

github.com

使うためにはhttps://deno.land/x/から始まるURLを指定してモジュールをimportする必要があります。
例えば今回紹介するテストモジュールの場合は

import { test, assert, equal, assertEqual } from 'https://deno.land/x/testing/mod.ts';

のように書きます。
実行のたびにHTTPリクエストするわけではなく、一回ダウンロードするとローカルにキャッシュされます。
ダウンロード先は $HOME/.deno/deps/ です。'https://deno.land/x/testing/mod.ts' は、 $HOME/.deno/deps/https/deno.land/x/testing/mod.ts にあります。

テストモジュールについて

今回コミットしたREADMEに書いたサンプルコードとAPIについて紹介します。

deno_std/README.md at master · denoland/deno_std · GitHub

import { test, assert, equal, assertEqual } from 'https://deno.land/x/testing/mod.ts';

test({
  name: 'testing example',
  fn() {
    assert(equal("world", "world"));
    assert(!equal("hello", "world"));
    assert(equal({ hello: "world" }, { hello: "world" }));
    assert(!equal({ world: "hello" }, { hello: "world" }));
    assertEqual("world", "world");
    assertEqual({hello: "world"}, {hello: "world"});
  },
});

Short syntax (named function instead of object):

test(function example() {
  assert(equal("world", "world"));
  assert(!equal("hello", "world"));
  assert(equal({ hello: "world" }, { hello: "world" }));
  assert(!equal({ world: "hello" }, { hello: "world" }));
  assertEqual("world", "world");
  assertEqual({hello: "world"}, {hello: "world"});
});

test

testという関数を使ってテストを実行します。
testには2パターンの使い方があります。

  • namefnを持ったオブジェクトを渡す
  • named functionを渡す

型は以下の通りです。

export type TestFunction = () => void | Promise<void>;

export interface TestDefinition {
  fn: TestFunction;
  name: string;
}

export function test(t: TestDefinition | TestFunction): void 

assert

これはbooleanを引数に取るアサーション関数です。
基本的に後述するequalと一緒に使います。

assert(expr: boolean, msg = "") 

となっていて第一引数は比較結果をbooleanで渡し、第二引数は失敗時のエラーメッセージを渡します。

equal

これは期待値と結果の値を比較してbooleanを返す関数です。
成功ならtrueを失敗ならfalseを返します。
上記のサンプルコードにもありますが、Objectも比較してくれます。また、Objectの中のObjectも判定してくれます。

equal(
  { hello: "world", hi: { there: "everyone" } },
  { hello: "world", hi: { there: "everyone else" } }
)

型は以下の通りでunknownを取るので何でも渡せます。

equal(actual: unknown, expected: unknown): boolean

assertEqual

これは前述のassertとequalを組み合わせたみたいな関数です。
実際、内部の判定は前述のequalを使っています。 型は以下の通りです。

assertEqual(actual: unknown, expected: unknown, msg?: string)

最後のmsgは失敗時に表示するエラーメッセージです。メッセージを渡さない場合はデフォルトのError: actual: ${actual} expected: ${expected}が表示されます。

デフォルトのエラーメッセージは変数をそのままテンプレートリテラルで埋め込むためObjectの比較で失敗したときのメッセージが不親切です。

f:id:Shisama:20190105141654p:plain
標準のassertEqualの失敗時のエラーメッセージ

しかし失敗したObjectの内容を表示してくれるpretty_assertという便利なライブラリを使うと以下のように表示されます。

f:id:Shisama:20190105142310p:plain
pretty_assertを使った失敗時のエラーメッセージ

github.com

あとがき

Denoの標準モジュールはNode.jsのようにCoreに内包しているのではなく、必要なときだけ外部からダウンロードして使うという方式をとっていて面白いです。
標準モジュールは他にもnetloggingなどあります。
netを使った簡易Webサーバを起動する記事をQiitaに書いたので興味あれば読んでみてください。

qiita.com

最後までお読みいただきありがとうございました。質問や不備があればTwitter(@shisama_)までお願いします。