Deno 2中KV测试出现‘close resource’错误的原因
Deno Kv测试资源泄漏报错的原因及解决方法
问题描述
我针对Deno Kv数据库编写了数据查询测试,通过beforeAll打开数据库并添加测试数据,afterAll关闭连接并删除数据库文件。所有测试用例均通过,但describe层级测试抛出资源泄漏错误:
getUserActions => https://jsr.io/@std/testing/1.0.4/_test_suite.ts:218:10 error: Leaks detected: - "database" was created during the test, but not cleaned up during the test. Close the resource before the end of the test.
已确认Kv数据文件确实被删除,但测试框架仍提示资源未清理,请问错误原因是什么?
相关代码片段:
测试代码
import { expect } from "jsr:@std/expect"; import { afterAll, beforeAll, describe, it } from "jsr:@std/testing/bdd"; describe("getUserActions", () => { let kv: Deno.Kv; beforeAll(async () => { kv = await Deno.openKv("./test_data"); await seedTestUserActionData(); }); afterAll(async () => { await kv.close(); console.log("start delete"); await deleteTestKv(); console.log("end delete"); }); // 后续测试用例... });
数据库删除函数
export async function deleteTestKv( dbPath: string = "./test_data" ): Promise<void> { await closeDb(dbPath); try { // 删除前检查文件是否存在 await Deno.stat(dbPath); await Deno.remove(dbPath); await Deno.remove(dbPath + "-shm"); await Deno.remove(dbPath + "-wal"); } catch (error) { if (error instanceof Deno.errors.NotFound) { console.log(`Database file ${dbPath} not found`); } else { console.log("Remove error:", error); } } } async function closeDb(dbPath: string): Promise<void> { try { // 尝试关闭现有连接 const kv = await Deno.openKv(dbPath); await kv.close(); } catch (error) { console.log("Close error:", error); } }
错误原因
问题出在deleteTestKv函数调用的closeDb方法中:
- 你已经在
afterAll里关闭了kv变量对应的数据库连接,但closeDb又重新调用Deno.openKv(dbPath)创建了一个新的数据库连接。 - 虽然这个临时连接被立即关闭,但Deno的测试框架资源泄漏检测会捕捉到这次创建的数据库资源,判定为未清理的资源,从而抛出错误。
- 数据库文件被删除只是磁盘文件的清理,但测试框架检测的是内存中未释放的资源句柄,这次临时创建的连接触发了检测逻辑。
解决方法
方法一:移除重复的连接关闭逻辑
既然已经在afterAll中关闭了数据库连接,无需在删除文件前重复尝试关闭。修改deleteTestKv函数:
export async function deleteTestKv( dbPath: string = "./test_data" ): Promise<void> { try { // 直接删除数据库相关文件 await Deno.remove(dbPath); await Deno.remove(dbPath + "-shm"); await Deno.remove(dbPath + "-wal"); } catch (error) { if (error instanceof Deno.errors.NotFound) { console.log(`Database file ${dbPath} not found`); } else { console.log("Remove error:", error); } } }
方法二:使用临时目录管理测试数据库
推荐使用Deno的临时目录功能,避免手动管理单个文件,同时彻底隔离测试环境:
describe("getUserActions", () => { let kv: Deno.Kv; let tempDir: string; beforeAll(async () => { // 创建临时目录 tempDir = await Deno.makeTempDir(); kv = await Deno.openKv(`${tempDir}/test_data`); await seedTestUserActionData(); }); afterAll(async () => { await kv.close(); // 递归删除整个临时目录 await Deno.remove(tempDir, { recursive: true }); }); // 测试用例... });
这种方式无需手动处理单个数据库文件,测试结束后直接删除整个目录,既干净又能避免资源泄漏问题。
内容的提问来源于stack exchange,提问作者Clayton Ingalls
相关产品推荐
相关产品推荐

