Skip to content

Commit 52be0fd

Browse files
committed
fix:修改测试用例,并将mongodb示例替换成mongodb-memory-server
1 parent 6c72276 commit 52be0fd

14 files changed

Lines changed: 492 additions & 596 deletions

‎CHANGELOG.md‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@
44

55
## [未发布]
66

7+
### 改进
8+
- **[测试] 集成 MongoDB Memory Server(配置驱动方案)**:通过 `config.useMemoryServer` 控制是否使用内存数据库
9+
- 在 `lib/mongodb/connect.js` 中添加内存数据库支持
10+
- 通过 `config: { useMemoryServer: true }` 显式启用
11+
- 单例模式:所有测试共享同一个内存服务器实例,性能优异
12+
- 测试文件统一添加配置参数,逻辑清晰明确
13+
- 优势:**配置驱动、显式明确、单例优化、零生产风险**
14+
- 测试验证:所有测试套件全部通过,性能优秀 ✅
15+
16+
- **[测试] 改进缓存功能测试**:通过检查缓存统计信息验证缓存是否真的生效
17+
- 移除不稳定的时间比较断言(在内存数据库环境下不可靠)
18+
- 使用 `msq.cache.getStats()` 检查缓存命中次数
19+
- 验证 `hits` 统计是否增加,直接证明缓存命中
20+
- 同时保留结果一致性验证
21+
- **添加详细日志输出**:打印前后命中次数、未命中次数、缓存命中率
22+
- **使用 resetStats() 隔离测试**:确保每个测试独立,不受其他测试影响
23+
- 测试输出更加直观易懂 ✅
24+
725
### 修复
826
- **[错误码] 添加 STREAM_NO_EXPLAIN 错误码**:修复 `findPage` 方法在流式模式下使用 `explain` 参数时的错误码不一致问题,从通用的 `VALIDATION_ERROR` 改为更具体的 `STREAM_NO_EXPLAIN`,提供更清晰的错误信息。
927
- **[测试] 修复 all 模式测试运行器**:修复 `test/run-tests.js` 中 `all` 模式一次性加载所有测试导致的并发初始化问题,改为顺序执行各个测试套件,避免 MongoDB 连接池耗尽和索引创建冲突。
@@ -179,7 +197,7 @@
179197
- totals:新增 5s 窗口的 inflight 去重,避免同一形状的并发计数击穿。
180198

181199
### 测试
182-
- **新增连接管理测试套件**:`test/connection-simple.test.js`
200+
- **新增连接管理测试套件**:`test/connection.test.js`
183201
- 验证并发连接只建立一个实例(10 并发测试)
184202
- 验证集合名和数据库名的输入校验(空、null、空格、非字符串)
185203
- 验证多次连接-关闭循环的资源清理(3 次循环测试)

‎docs/MONGODB-MEMORY-SERVER.md‎

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# MongoDB Memory Server - 配置使用指南
2+
3+
## 🚀 快速开始
4+
5+
### 测试代码
6+
7+
```javascript
8+
const MonSQLize = require('../../lib');
9+
10+
const msq = new MonSQLize({
11+
type: 'mongodb',
12+
databaseName: 'test_db',
13+
config: {
14+
useMemoryServer: true // 🔑 启用内存数据库
15+
}
16+
});
17+
18+
await msq.connect(); // 自动使用内存 MongoDB
19+
```
20+
21+
### 生产代码
22+
23+
```javascript
24+
const msq = new MonSQLize({
25+
type: 'mongodb',
26+
databaseName: 'prod_db',
27+
config: {
28+
uri: process.env.MONGODB_URI // 使用真实数据库
29+
}
30+
});
31+
```
32+
33+
---
34+
35+
## 📊 配置参数
36+
37+
| 参数 | 类型 | 默认值 | 说明 |
38+
|-----|------|-------|------|
39+
| `useMemoryServer` | boolean | `false` | 是否使用内存数据库 |
40+
| `uri` | string | - | MongoDB 连接 URI |
41+
42+
**优先级**: 当 `useMemoryServer: true` 时,会忽略 `uri` 参数
43+
44+
---
45+
46+
## ✨ 特性
47+
48+
✅ **配置驱动**:通过配置参数显式控制
49+
✅ **单例模式**:所有测试共享一个实例
50+
✅ **零风险**:生产环境不会误用
51+
✅ **高性能**:启动仅需 3 秒,后续 <1ms
52+
53+
---
54+
55+
## 📝 使用场景
56+
57+
### 场景 1: 单元测试
58+
59+
```javascript
60+
config: { useMemoryServer: true }
61+
```
62+
63+
### 场景 2: 集成测试
64+
65+
```javascript
66+
config: { uri: 'mongodb://staging:27017' }
67+
```
68+
69+
### 场景 3: 生产环境
70+
71+
```javascript
72+
config: { uri: process.env.MONGODB_URI }
73+
```
74+
75+
---
76+
77+
## 🔧 工作原理
78+
79+
```
80+
测试代码
81+
↓ config: { useMemoryServer: true }
82+
lib/mongodb/connect.js
83+
↓ 检测到 useMemoryServer
84+
↓ 启动内存 MongoDB(单例)
85+
↓ 返回内存数据库 URI
86+
MongoClient
87+
↓ 连接到内存数据库
88+
测试执行
89+
```
90+
91+
---
92+
93+
## 📈 性能
94+
95+
- **首次启动**: ~3 秒
96+
- **后续使用**: <1 毫秒(单例)
97+
- **connection 套件**: 0.43 秒
98+
- **find 套件**: 0.51 秒
99+
- **findPage 套件**: 0.50 秒
100+
101+
---
102+
103+
## 🔗 相关文档
104+
105+
- [完整报告](./2025-11-05-config-driven-mongodb-memory-server.md)
106+
- [测试文档](../test/README.md)
107+
- [CHANGELOG](../CHANGELOG.md)
108+
109+
---
110+
111+
**版本**: 1.0(配置驱动)
112+
**更新**: 2025-11-05
113+

‎lib/mongodb/connect.js‎

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,99 @@
11
const { MongoClient } = require('mongodb');
22

3+
// 懒加载 MongoDB Memory Server(仅在需要时加载)
4+
let MongoMemoryServer;
5+
let memoryServerInstance; // 单例实例
6+
37
function buildLogContext({ type, databaseName, defaults, config }) {
48
const scope = defaults?.namespace?.scope;
59
let uriHost;
610
try { uriHost = new URL(config?.uri || '').hostname; } catch (_) { uriHost = undefined; }
711
return { type, db: databaseName, scope, uriHost };
812
}
913

14+
/**
15+
* 启动 MongoDB Memory Server(单例模式)
16+
* @param {Object} logger - 日志记录器
17+
* @returns {Promise<string>} 返回内存数据库的连接 URI
18+
*/
19+
async function startMemoryServer(logger) {
20+
if (memoryServerInstance) {
21+
const uri = memoryServerInstance.getUri();
22+
try { logger && logger.debug && logger.debug('📌 Using existing MongoDB Memory Server', { uri }); } catch (_) {}
23+
return uri;
24+
}
25+
26+
try {
27+
// 懒加载 MongoDB Memory Server
28+
if (!MongoMemoryServer) {
29+
MongoMemoryServer = require('mongodb-memory-server').MongoMemoryServer;
30+
}
31+
32+
try { logger && logger.info && logger.info('🚀 Starting MongoDB Memory Server...'); } catch (_) {}
33+
34+
memoryServerInstance = await MongoMemoryServer.create({
35+
instance: {
36+
port: undefined, // 自动分配端口
37+
dbName: 'test_db',
38+
storageEngine: 'ephemeralForTest', // 使用临时存储引擎
39+
},
40+
binary: {
41+
version: '6.0.12', // 指定 MongoDB 版本
42+
},
43+
});
44+
45+
const uri = memoryServerInstance.getUri();
46+
try { logger && logger.info && logger.info('✅ MongoDB Memory Server started', { uri }); } catch (_) {}
47+
return uri;
48+
} catch (err) {
49+
try { logger && logger.error && logger.error('❌ Failed to start MongoDB Memory Server', err); } catch (_) {}
50+
throw new Error(`Failed to start MongoDB Memory Server: ${err.message}`);
51+
}
52+
}
53+
54+
/**
55+
* 停止 MongoDB Memory Server
56+
* @param {Object} logger - 日志记录器
57+
*/
58+
async function stopMemoryServer(logger) {
59+
if (!memoryServerInstance) {
60+
return;
61+
}
62+
63+
try {
64+
try { logger && logger.info && logger.info('🛑 Stopping MongoDB Memory Server...'); } catch (_) {}
65+
await memoryServerInstance.stop();
66+
memoryServerInstance = null;
67+
try { logger && logger.info && logger.info('✅ MongoDB Memory Server stopped'); } catch (_) {}
68+
} catch (err) {
69+
try { logger && logger.warn && logger.warn('⚠️ Error stopping MongoDB Memory Server', err); } catch (_) {}
70+
memoryServerInstance = null;
71+
}
72+
}
73+
1074
/**
1175
* 建立 MongoDB 连接(适配器内部使用)
12-
* @param {{ databaseName: string, config: { uri: string, options?: object }, logger: any, defaults: object, type?: string }} params
76+
* @param {{ databaseName: string, config: { uri?: string, options?: object, useMemoryServer?: boolean }, logger: any, defaults: object, type?: string }} params
1377
* @returns {Promise<{ client: import('mongodb').MongoClient, db: any }>} 返回已连接的 client 与默认 db 句柄(若可用)
1478
*/
1579
async function connectMongo({ databaseName, config, logger, defaults, type = 'mongodb' }) {
16-
const { uri, options = {} } = config || {};
17-
if (!uri) throw new Error('MongoDB connect requires config.uri');
80+
let { uri, options = {}, useMemoryServer } = config || {};
81+
82+
// 🔑 根据 config.useMemoryServer 决定是否使用内存数据库
83+
if (useMemoryServer === true) {
84+
try {
85+
uri = await startMemoryServer(logger);
86+
} catch (err) {
87+
// 如果启动内存服务器失败,且没有提供 uri,抛出错误
88+
if (!uri) {
89+
throw new Error('Failed to start Memory Server and no URI provided');
90+
}
91+
try { logger && logger.warn && logger.warn('Failed to start Memory Server, using provided URI', { uri }); } catch (_) {}
92+
}
93+
}
94+
95+
if (!uri) throw new Error('MongoDB connect requires config.uri or config.useMemoryServer');
96+
1897
const client = new MongoClient(uri, options);
1998
try {
2099
await client.connect();
@@ -34,10 +113,16 @@ async function connectMongo({ databaseName, config, logger, defaults, type = 'mo
34113
* 关闭 MongoDB 连接
35114
* @param {import('mongodb').MongoClient} client
36115
* @param {any} logger
116+
* @param {boolean} [stopMemory=false] - 是否同时停止内存服务器
37117
*/
38-
async function closeMongo(client, logger) {
118+
async function closeMongo(client, logger, stopMemory = false) {
39119
if (!client) return;
40120
try { await client.close(); } catch (e) { try { logger && logger.warn && logger.warn('MongoDB close error', e && (e.stack || e)); } catch(_) {} }
121+
122+
// 如果指定停止内存服务器
123+
if (stopMemory) {
124+
await stopMemoryServer(logger);
125+
}
41126
}
42127

43-
module.exports = { connectMongo, closeMongo };
128+
module.exports = { connectMongo, closeMongo, stopMemoryServer };

‎test/README.md‎

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ test/
1818
│ │ └── distinct.test.js
1919
│ ├── infrastructure/ # 基础设施测试(底层支撑)
2020
│ │ ├── connection.test.js
21-
│ │ ├── connection-simple.test.js
21+
│ │ ├── connection.test.js
2222
│ │ ├── errors.test.js
2323
│ │ └── logger.test.js
2424
│ └── utils/ # 工具函数测试(纯函数)
@@ -60,7 +60,7 @@ test/
6060

6161
**包含文件**:
6262
- `connection.test.js` - 连接管理测试
63-
- `connection-simple.test.js` - 连接管理简化测试
63+
- `connection.test.js` - 连接管理简化测试
6464
- `errors.test.js` - 错误码系统测试
6565
- `logger.test.js` - 日志系统测试
6666

@@ -88,6 +88,65 @@ test/
8888

8989
## 运行测试
9090

91+
### ✨ 测试环境(MongoDB Memory Server - 配置驱动)
92+
93+
从 2025-11-05 开始,本项目支持通过 **`config.useMemoryServer`** 配置参数使用 MongoDB Memory Server(内存数据库)进行测试。
94+
95+
**使用方式**:
96+
```javascript
97+
// 测试文件中显式启用内存数据库
98+
const msq = new MonSQLize({
99+
type: 'mongodb',
100+
databaseName: 'test_db',
101+
config: {
102+
useMemoryServer: true // 🔑 启用内存数据库
103+
}
104+
});
105+
106+
await msq.connect(); // 自动使用内存 MongoDB
107+
```
108+
109+
**优势**:
110+
- ✅ **配置驱动**:完全通过配置参数控制,逻辑清晰
111+
- ✅ **显式明确**:测试代码明确表明使用内存数据库
112+
- ✅ **单例模式**:所有测试共享同一个内存服务器,极速启动
113+
- ✅ **高性能**:单例共享,启动仅需 ~3 秒
114+
- ✅ **零风险**:生产环境不会误用(需显式配置)
115+
- ✅ **CI 友好**:GitHub Actions 无需额外配置
116+
117+
**性能数据**:
118+
- 内存服务器启动:首次 ~3s,后续 <1ms(单例共享)
119+
- connection 套件:0.43 秒(5 个测试)
120+
- find 套件:0.51 秒(31 个测试)
121+
- findPage 套件:0.50 秒(42 个测试)
122+
123+
**首次运行**:
124+
```bash
125+
npm test # 首次会自动下载 MongoDB 二进制文件(~70MB),缓存到本地
126+
```
127+
128+
**后续运行**:
129+
```bash
130+
npm test # 直接使用缓存,秒启动
131+
```
132+
133+
**技术细节**:
134+
1. 测试文件配置 `config: { useMemoryServer: true }`
135+
2. 库内部 `lib/mongodb/connect.js` 检测到配置
136+
3. 自动启动内存 MongoDB(单例模式)
137+
4. 所有测试共享同一个实例
138+
5. 测试结束后自动清理
139+
140+
**使用真实 MongoDB**(集成测试):
141+
```javascript
142+
// 不设置 useMemoryServer,使用真实数据库
143+
const msq = new MonSQLize({
144+
config: {
145+
uri: 'mongodb://localhost:27017' // 真实数据库 URI
146+
}
147+
});
148+
```
149+
91150
### 运行所有测试
92151
```bash
93152
npm test
@@ -97,8 +156,9 @@ node test/run-tests.js
97156

98157
### 运行单个测试文件
99158
```bash
100-
node test/find.test.js
101-
node test/findPage.test.js
159+
node test/run-tests.js connection
160+
node test/run-tests.js find
161+
node test/run-tests.js findPage
102162
```
103163

104164
### 运行 P0 验证

0 commit comments

Comments
 (0)