测试清理器
deno test 运行器提供了多个清理器,
用于捕获测试中 assertion 无法发现的异常行为:泄漏的异步
操作、未关闭的资源以及意外的进程退出。
资源清理器 Jump to heading
资源清理器会确保测试期间创建的所有 I/O 资源都已关闭, 以防止泄漏。
I/O 资源包括例如 Deno.FsFile 句柄、
网络连接、fetch 响应体、计时器,以及其他
不会被自动垃圾回收的资源。
你应该在完成使用后始终关闭资源。例如,关闭文件:
const file = await Deno.open("hello.txt");
// 对文件执行一些操作
file.close(); // <- 使用完文件后始终关闭它
关闭网络连接:
const conn = await Deno.connect({ hostname: "example.com", port: 80 });
// 对连接执行一些操作
conn.close(); // <- 使用完连接后始终关闭它
关闭 fetch 响应体:
const response = await fetch("https://example.com");
// 对响应执行一些操作
await response.body?.cancel(); // <- 如果没有以其他方式消费它,使用完后始终取消响应体
从 Deno 2.8 开始,此清理器默认关闭。你可以通过
sanitizeResources: true 启用它,或使用
全局启用清理器 中描述的全局机制之一。
Deno.test({
name: "不允许泄漏",
async fn() {
using file = await Deno.open("hello.txt");
// ...
},
sanitizeResources: true,
});
异步操作清理器 Jump to heading
异步操作清理器会确保测试中启动的所有异步操作都在 测试结束前完成。这一点很重要,因为如果某个异步 操作没有被 await,测试会在该操作完成前结束, 即使该操作实际上可能已经失败,测试也会被标记为成功。
你应该在测试中始终 await 所有异步操作。例如:
Deno.test({
name: "异步操作测试",
async fn() {
await new Promise((resolve) => setTimeout(resolve, 1000));
},
});
从 Deno 2.8 开始,此清理器默认关闭。你可以通过
sanitizeOps: true 启用它,或使用下面描述的全局机制之一。
Deno.test({
name: "不允许泄漏的操作",
async fn() {
await someAsyncWork();
},
sanitizeOps: true,
});
全局启用清理器 Jump to heading
如果你想要 pre-2.8 的行为(对每个测试都开启资源和操作清理器), 可以在以下五个作用域中的任意一个重新启用它们。更高优先级的设置 会覆盖更低优先级的设置。
-
按测试(最高优先级):
Deno.test({ name: "严格模式", sanitizeOps: true, sanitizeResources: true, fn() {/* … */}, }); -
按模块,使用
Deno.test.sanitizer():Deno.test.sanitizer({ ops: true, resources: true }); Deno.test("使用模块级清理器", () => {/* … */}); -
CLI 标志:
--sanitize-ops和--sanitize-resources。 -
环境变量:
DENO_TEST_SANITIZE_OPS=1和DENO_TEST_SANITIZE_RESOURCES=1。 -
deno.json(最低优先级):{ "test": { "sanitizeOps": true, "sanitizeResources": true } }
退出清理器 Jump to heading
退出清理器会确保被测试的代码不会调用
Deno.exit(),因为这可能会造成测试成功的假象。
此清理器默认启用,但可以通过
sanitizeExit: false 关闭。
Deno.test({
name: "错误的成功",
fn() {
Deno.exit(0);
},
sanitizeExit: false,
});
// 这个测试永远不会运行,因为进程会在“错误的成功”测试期间退出
Deno.test({
name: "失败的测试",
fn() {
throw new Error("这个测试失败了");
},
});