Denoのテストで下記のようにsubprocessを使って、コマンド実行結果をテストしようとした。
Deno.test({ name: "test name", fn: async () => { const p = Deno.run({ cmd: [ /*コマンド*/], stdout: "piped", }); const { code } = await p.status(); // 返り値が0であることを確認 assertEquals(code, 0); const rawOutput = await p.output(); const stdoutResult = new TextDecoder().decode(rawOutput).trim(); // コマンドの実行結果が"foo"であることを確認 assertEquals(stdoutResult, "foo"); } });
だが、このテストをdeno test --allow-run で実行しようとすると、下記のようなエラーとなる。
AssertionError: Test case is leaking resources.
Before: {
"0": "stdin",
"1": "stdout",
"2": "stderr"
}
After: {
"0": "stdin",
"1": "stdout",
"2": "stderr",
"4": "child"
}
Make sure to close all open resource handles returned from Deno APIs before
finishing test case.
どうやら開放されていないリソースがあるとこのようなエラーが表示されるらしい。
インターネットで検索してみたところ、日本語で書かれた解説を見つけたので下記に貼る。
(Zennで無償で公開されている Effective Deno内の内容となる)
そしてこのリソース開放に関するエラーを解消するためには下記のような対象方法がある。
が、これは上で紹介した書籍内にも書かれているが、あまりおすすめされた方法ではなく、本来であればリソース開放のための処理を記載する必要がある。
Deno.test({ name: "test name", fn: async () => { const p = Deno.run({ cmd: [ /*コマンド*/], stdout: "piped", }); const { code } = await p.status(); // 返り値が0であることを確認 assertEquals(code, 0); const rawOutput = await p.output(); const stdoutResult = new TextDecoder().decode(rawOutput).trim(); // コマンドの実行結果が"foo"であることを確認 assertEquals(stdoutResult, "foo"); }, sanitizeResources: false, sanitizeOps: false, });
では、今回のようなsubprocessを用いた例の場合、どうすればよいかと思い調べていたところ、aleph.js 内のとあるPRのテストの書き方が参考になった。
(しかも偶然にも上で紹介したEffective Denoの作者の方が出したPRだった)
こちらの書き方を参考に下記のようにコードを修正した。
Deno.test({ name: "test name", fn: async () => { const p = Deno.run({ cmd: [ /*コマンド*/], stdout: "piped", }); const { code } = await p.status(); // 返り値が0であることを確認 assertEquals(code, 0); const rawOutput = await p.output(); const stdoutResult = new TextDecoder().decode(rawOutput).trim(); // コマンドの実行結果が"foo"であることを確認 assertEquals(stdoutResult, "foo"); // リソースを閉じる await p.close(); } });
これでリソース開放に関する表示は解消された。
以上、備忘録でした。