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(); } });
これでリソース開放に関する表示は解消された。
以上、備忘録でした。