mm_mysql 2.0.3 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +360 -1030
- package/package.json +1 -1
- package/sql.js +89 -0
- package/test.js +518 -0
package/package.json
CHANGED
package/sql.js
CHANGED
|
@@ -1625,4 +1625,93 @@ Sql.prototype.model = function (model) {
|
|
|
1625
1625
|
});
|
|
1626
1626
|
};
|
|
1627
1627
|
|
|
1628
|
+
/**
|
|
1629
|
+
* 添加或修改数据(存在则修改,不存在则添加)
|
|
1630
|
+
* @param {Object|String} where 查询条件
|
|
1631
|
+
* @param {Object|String} set 要设置的数据
|
|
1632
|
+
* @param {Boolean} like 是否使用like匹配, 为空使用默认方式
|
|
1633
|
+
* @return {Promise<Object>} 执行结果
|
|
1634
|
+
*/
|
|
1635
|
+
Sql.prototype.addOrSet = async function(where, set, like) {
|
|
1636
|
+
if (!this.table || !where || !set) {
|
|
1637
|
+
throw new Error('表名、条件或数据未设置');
|
|
1638
|
+
}
|
|
1639
|
+
try {
|
|
1640
|
+
let query = where;
|
|
1641
|
+
let body = set;
|
|
1642
|
+
let whereStr;
|
|
1643
|
+
|
|
1644
|
+
if (typeof where === "object") {
|
|
1645
|
+
whereStr = await this.toWhere(where, like);
|
|
1646
|
+
} else {
|
|
1647
|
+
whereStr = where;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
const count = await this.countSql(whereStr);
|
|
1651
|
+
|
|
1652
|
+
if (count === 0) {
|
|
1653
|
+
let key = "";
|
|
1654
|
+
let value = "";
|
|
1655
|
+
|
|
1656
|
+
if (typeof set === "string") {
|
|
1657
|
+
const arr = set.split(",");
|
|
1658
|
+
for (const o of arr) {
|
|
1659
|
+
const ar = o.split('=');
|
|
1660
|
+
if (ar.length === 2) {
|
|
1661
|
+
key += "," + ar[0];
|
|
1662
|
+
value += "," + ar[1];
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
} else {
|
|
1666
|
+
// 触发前置事件
|
|
1667
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof body === "object") {
|
|
1668
|
+
await $.eventer.run("mysql_add_before:" + this.table, { body });
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
for (const k in set) {
|
|
1672
|
+
if (!Object.prototype.hasOwnProperty.call(set, k)) continue;
|
|
1673
|
+
|
|
1674
|
+
key += "," + escapeId(k);
|
|
1675
|
+
let val = set[k];
|
|
1676
|
+
if (typeof val === "string") {
|
|
1677
|
+
val = val.trim("'");
|
|
1678
|
+
}
|
|
1679
|
+
value += "," + escape(val);
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
const bl = await this.addSql(key.replace(",", ""), value.replace(",", ""));
|
|
1684
|
+
|
|
1685
|
+
// 触发后置事件
|
|
1686
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof body === "object") {
|
|
1687
|
+
await $.eventer.run("mysql_add_after:" + this.table, { body, sql: this.sql, error: this.error, bl });
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
return bl;
|
|
1691
|
+
} else {
|
|
1692
|
+
// 触发前置事件
|
|
1693
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof set === "object") {
|
|
1694
|
+
await $.eventer.run("mysql_set_before:" + this.table, { query, body, like, page: this.page, size: this.size, sql: this.sql });
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
if (typeof set === "object") {
|
|
1698
|
+
set = await this.toSet(set);
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
const bl1 = await this.setSql(whereStr, set);
|
|
1702
|
+
|
|
1703
|
+
// 触发后置事件
|
|
1704
|
+
if (typeof $.eventer === 'object' && typeof $.eventer.run === 'function' && typeof body === "object") {
|
|
1705
|
+
await $.eventer.run("mysql_set_after:" + this.table, { query, body, like, page: this.page, size: this.size, sql: this.sql, error: this.error, bl: bl1 });
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
return bl1;
|
|
1709
|
+
}
|
|
1710
|
+
} catch (err) {
|
|
1711
|
+
this.error = err.message;
|
|
1712
|
+
$.log.error(`添加或修改数据失败: ${err.message}`);
|
|
1713
|
+
throw err;
|
|
1714
|
+
}
|
|
1715
|
+
};
|
|
1716
|
+
|
|
1628
1717
|
module.exports = Sql;
|
package/test.js
ADDED
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MySQL数据库操作类测试文件
|
|
3
|
+
* @file test.js
|
|
4
|
+
* @description 测试Mysql类的各项功能
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// 引入依赖
|
|
8
|
+
const { Mysql } = require('./index.js');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 测试类
|
|
12
|
+
* @class TestMysql
|
|
13
|
+
*/
|
|
14
|
+
class TestMysql {
|
|
15
|
+
/**
|
|
16
|
+
* 构造函数
|
|
17
|
+
* @param {Object} config - 数据库配置
|
|
18
|
+
*/
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.config = Object.assign({
|
|
21
|
+
host: '127.0.0.1',
|
|
22
|
+
port: 3306,
|
|
23
|
+
user: 'root',
|
|
24
|
+
password: '',
|
|
25
|
+
database: '', // 先不指定数据库,连接成功后再创建
|
|
26
|
+
debug: true,
|
|
27
|
+
connectionLimit: 5
|
|
28
|
+
}, config || {});
|
|
29
|
+
|
|
30
|
+
this._mysql = null;
|
|
31
|
+
this._test_results = [];
|
|
32
|
+
this._test_table_name = 'test_users';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 初始化测试环境
|
|
38
|
+
* @returns {Promise<boolean>}
|
|
39
|
+
*/
|
|
40
|
+
TestMysql.prototype._init = async function() {
|
|
41
|
+
try {
|
|
42
|
+
console.log('=== 初始化测试环境 ===');
|
|
43
|
+
|
|
44
|
+
// 创建Mysql实例(先不指定数据库)
|
|
45
|
+
this._mysql = new Mysql(this.config);
|
|
46
|
+
|
|
47
|
+
// 连接数据库
|
|
48
|
+
await this._mysql.open();
|
|
49
|
+
|
|
50
|
+
// 创建测试数据库
|
|
51
|
+
await this._create_test_database();
|
|
52
|
+
|
|
53
|
+
// 重新连接指定数据库
|
|
54
|
+
await this._mysql.close();
|
|
55
|
+
this.config.database = 'test_db';
|
|
56
|
+
this._mysql = new Mysql(this.config);
|
|
57
|
+
await this._mysql.open();
|
|
58
|
+
|
|
59
|
+
// 创建测试表
|
|
60
|
+
await this._create_test_table();
|
|
61
|
+
|
|
62
|
+
console.log('测试环境初始化完成');
|
|
63
|
+
return true;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error('初始化测试环境失败:', error.message);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 创建测试数据库
|
|
72
|
+
* @returns {Promise<boolean>}
|
|
73
|
+
*/
|
|
74
|
+
TestMysql.prototype._create_test_database = async function() {
|
|
75
|
+
try {
|
|
76
|
+
const create_db_sql = `CREATE DATABASE IF NOT EXISTS test_db`;
|
|
77
|
+
await this._mysql.exec(create_db_sql);
|
|
78
|
+
console.log('测试数据库创建成功');
|
|
79
|
+
return true;
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error('创建测试数据库失败:', error.message);
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 创建测试表
|
|
88
|
+
* @returns {Promise<boolean>}
|
|
89
|
+
*/
|
|
90
|
+
TestMysql.prototype._create_test_table = async function() {
|
|
91
|
+
try {
|
|
92
|
+
const sql = `
|
|
93
|
+
CREATE TABLE IF NOT EXISTS ${this._test_table_name} (
|
|
94
|
+
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
95
|
+
name VARCHAR(100) NOT NULL,
|
|
96
|
+
email VARCHAR(100) UNIQUE NOT NULL,
|
|
97
|
+
age INT,
|
|
98
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
99
|
+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
100
|
+
)
|
|
101
|
+
`;
|
|
102
|
+
|
|
103
|
+
await this._mysql.exec(sql);
|
|
104
|
+
console.log('测试表创建成功');
|
|
105
|
+
return true;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error('创建测试表失败:', error.message);
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 清理测试数据
|
|
114
|
+
* @returns {Promise<boolean>}
|
|
115
|
+
*/
|
|
116
|
+
TestMysql.prototype._cleanup = async function() {
|
|
117
|
+
try {
|
|
118
|
+
const sql = `DROP TABLE IF EXISTS ${this._test_table_name}`;
|
|
119
|
+
await this._mysql.exec(sql);
|
|
120
|
+
console.log('测试数据清理完成');
|
|
121
|
+
return true;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error('清理测试数据失败:', error.message);
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 记录测试结果
|
|
130
|
+
* @param {String} test_name - 测试名称
|
|
131
|
+
* @param {Boolean} success - 是否成功
|
|
132
|
+
* @param {String} message - 测试信息
|
|
133
|
+
*/
|
|
134
|
+
TestMysql.prototype._record_result = function(test_name, success, message) {
|
|
135
|
+
this._test_results.push({
|
|
136
|
+
test_name,
|
|
137
|
+
success,
|
|
138
|
+
message,
|
|
139
|
+
timestamp: new Date().toISOString()
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const status = success ? '✓' : '✗';
|
|
143
|
+
console.log(`${status} ${test_name}: ${message}`);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 测试连接功能
|
|
148
|
+
* @returns {Promise<boolean>}
|
|
149
|
+
*/
|
|
150
|
+
TestMysql.prototype.test_connection = async function() {
|
|
151
|
+
try {
|
|
152
|
+
// 测试获取连接
|
|
153
|
+
const conn = await this._mysql.getConn();
|
|
154
|
+
if (!conn) {
|
|
155
|
+
throw new Error('获取连接失败');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 测试连接是否可用
|
|
159
|
+
const [result] = await conn.execute('SELECT 1 as test_value');
|
|
160
|
+
if (!result || !Array.isArray(result) || result.length === 0) {
|
|
161
|
+
throw new Error('连接测试查询失败');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// 如果是连接池连接,需要释放
|
|
165
|
+
if (this._mysql._pool) {
|
|
166
|
+
conn.release();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
this._record_result('连接测试', true, '数据库连接正常');
|
|
170
|
+
return true;
|
|
171
|
+
} catch (error) {
|
|
172
|
+
this._record_result('连接测试', false, error.message);
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 测试插入功能
|
|
179
|
+
* @returns {Promise<boolean>}
|
|
180
|
+
*/
|
|
181
|
+
TestMysql.prototype.test_insert = async function() {
|
|
182
|
+
try {
|
|
183
|
+
const test_data = {
|
|
184
|
+
name: '测试用户',
|
|
185
|
+
email: 'test@example.com',
|
|
186
|
+
age: 25
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const sql = `INSERT INTO ${this._test_table_name} (name, email, age) VALUES (?, ?, ?)`;
|
|
190
|
+
const result = await this._mysql.exec(sql, [test_data.name, test_data.email, test_data.age]);
|
|
191
|
+
|
|
192
|
+
if (result.affectedRows !== 1) {
|
|
193
|
+
throw new Error('插入数据失败');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
this._record_result('插入测试', true, `插入成功,ID: ${result.insertId}`);
|
|
197
|
+
return true;
|
|
198
|
+
} catch (error) {
|
|
199
|
+
this._record_result('插入测试', false, error.message);
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 测试查询功能
|
|
206
|
+
* @returns {Promise<boolean>}
|
|
207
|
+
*/
|
|
208
|
+
TestMysql.prototype.test_query = async function() {
|
|
209
|
+
try {
|
|
210
|
+
// 查询所有数据
|
|
211
|
+
const sql = `SELECT * FROM ${this._test_table_name}`;
|
|
212
|
+
const results = await this._mysql.run(sql);
|
|
213
|
+
|
|
214
|
+
if (!Array.isArray(results)) {
|
|
215
|
+
throw new Error('查询结果格式异常');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
this._record_result('查询测试', true, `查询到 ${results.length} 条记录`);
|
|
219
|
+
return true;
|
|
220
|
+
} catch (error) {
|
|
221
|
+
this._record_result('查询测试', false, error.message);
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* 测试条件查询
|
|
228
|
+
* @returns {Promise<boolean>}
|
|
229
|
+
*/
|
|
230
|
+
TestMysql.prototype.test_conditional_query = async function() {
|
|
231
|
+
try {
|
|
232
|
+
const sql = `SELECT * FROM ${this._test_table_name} WHERE name = ?`;
|
|
233
|
+
const results = await this._mysql.run(sql, ['测试用户']);
|
|
234
|
+
|
|
235
|
+
if (!Array.isArray(results)) {
|
|
236
|
+
throw new Error('条件查询结果格式异常');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
this._record_result('条件查询测试', true, `查询到 ${results.length} 条匹配记录`);
|
|
240
|
+
return true;
|
|
241
|
+
} catch (error) {
|
|
242
|
+
this._record_result('条件查询测试', false, error.message);
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* 测试更新功能
|
|
249
|
+
* @returns {Promise<boolean>}
|
|
250
|
+
*/
|
|
251
|
+
TestMysql.prototype.test_update = async function() {
|
|
252
|
+
try {
|
|
253
|
+
const sql = `UPDATE ${this._test_table_name} SET age = ? WHERE name = ?`;
|
|
254
|
+
const result = await this._mysql.exec(sql, [30, '测试用户']);
|
|
255
|
+
|
|
256
|
+
if (result.affectedRows < 1) {
|
|
257
|
+
throw new Error('更新数据失败');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
this._record_result('更新测试', true, `更新了 ${result.affectedRows} 条记录`);
|
|
261
|
+
return true;
|
|
262
|
+
} catch (error) {
|
|
263
|
+
this._record_result('更新测试', false, error.message);
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* 测试删除功能
|
|
270
|
+
* @returns {Promise<boolean>}
|
|
271
|
+
*/
|
|
272
|
+
TestMysql.prototype.test_delete = async function() {
|
|
273
|
+
try {
|
|
274
|
+
const sql = `DELETE FROM ${this._test_table_name} WHERE name = ?`;
|
|
275
|
+
const result = await this._mysql.exec(sql, ['测试用户']);
|
|
276
|
+
|
|
277
|
+
if (result.affectedRows < 1) {
|
|
278
|
+
throw new Error('删除数据失败');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
this._record_result('删除测试', true, `删除了 ${result.affectedRows} 条记录`);
|
|
282
|
+
return true;
|
|
283
|
+
} catch (error) {
|
|
284
|
+
this._record_result('删除测试', false, error.message);
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* 测试事务功能
|
|
291
|
+
* @returns {Promise<boolean>}
|
|
292
|
+
*/
|
|
293
|
+
TestMysql.prototype.test_transaction = async function() {
|
|
294
|
+
try {
|
|
295
|
+
const result = await this._mysql.transaction(async (tx) => {
|
|
296
|
+
// 在事务中插入数据 - 使用Mysql类的exec方法
|
|
297
|
+
const insert_sql = `INSERT INTO ${this._test_table_name} (name, email, age) VALUES (?, ?, ?)`;
|
|
298
|
+
const insert_result = await this._mysql.exec(insert_sql, ['事务用户', 'tx@example.com', 28]);
|
|
299
|
+
|
|
300
|
+
// 在事务中查询数据 - 使用Mysql类的run方法
|
|
301
|
+
const query_sql = `SELECT * FROM ${this._test_table_name} WHERE email = ?`;
|
|
302
|
+
const results = await this._mysql.run(query_sql, ['tx@example.com']);
|
|
303
|
+
|
|
304
|
+
return results;
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
this._record_result('事务测试', true, '事务执行成功');
|
|
308
|
+
return true;
|
|
309
|
+
} catch (error) {
|
|
310
|
+
this._record_result('事务测试', false, error.message);
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* 测试连接池功能
|
|
317
|
+
* @returns {Promise<boolean>}
|
|
318
|
+
*/
|
|
319
|
+
TestMysql.prototype.test_connection_pool = async function() {
|
|
320
|
+
try {
|
|
321
|
+
if (!this._mysql._pool) {
|
|
322
|
+
this._record_result('连接池测试', true, '连接池未启用(单连接模式)');
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// 测试并发获取连接
|
|
327
|
+
const promises = [];
|
|
328
|
+
for (let i = 0; i < 3; i++) {
|
|
329
|
+
promises.push(this._mysql.getConn());
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const connections = await Promise.all(promises);
|
|
333
|
+
|
|
334
|
+
// 释放所有连接
|
|
335
|
+
connections.forEach(conn => {
|
|
336
|
+
if (conn.release) {
|
|
337
|
+
conn.release();
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
this._record_result('连接池测试', true, `并发获取 ${connections.length} 个连接成功`);
|
|
342
|
+
return true;
|
|
343
|
+
} catch (error) {
|
|
344
|
+
this._record_result('连接池测试', false, error.message);
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* 测试错误处理
|
|
351
|
+
* @returns {Promise<boolean>}
|
|
352
|
+
*/
|
|
353
|
+
TestMysql.prototype.test_error_handling = async function() {
|
|
354
|
+
try {
|
|
355
|
+
// 测试无效SQL
|
|
356
|
+
const invalid_sql = 'SELECT * FROM non_existent_table';
|
|
357
|
+
await this._mysql.run(invalid_sql);
|
|
358
|
+
|
|
359
|
+
this._record_result('错误处理测试', false, '应该抛出错误但未抛出');
|
|
360
|
+
return false;
|
|
361
|
+
} catch (error) {
|
|
362
|
+
if (error.code && error.code.startsWith('ER_')) {
|
|
363
|
+
this._record_result('错误处理测试', true, `正确捕获SQL错误: ${error.message}`);
|
|
364
|
+
return true;
|
|
365
|
+
} else {
|
|
366
|
+
this._record_result('错误处理测试', false, `捕获到非预期错误: ${error.message}`);
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* 运行所有测试
|
|
374
|
+
* @returns {Promise<Object>}
|
|
375
|
+
*/
|
|
376
|
+
TestMysql.prototype.run_all_tests = async function() {
|
|
377
|
+
console.log('\n=== 开始运行MySQL功能测试 ===\n');
|
|
378
|
+
|
|
379
|
+
// 初始化测试环境
|
|
380
|
+
const init_success = await this._init();
|
|
381
|
+
if (!init_success) {
|
|
382
|
+
console.log('测试环境初始化失败,跳过所有测试');
|
|
383
|
+
return this._get_test_summary();
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// 定义测试用例
|
|
387
|
+
const test_cases = [
|
|
388
|
+
{ name: '连接测试', method: 'test_connection' },
|
|
389
|
+
{ name: '插入测试', method: 'test_insert' },
|
|
390
|
+
{ name: '查询测试', method: 'test_query' },
|
|
391
|
+
{ name: '条件查询测试', method: 'test_conditional_query' },
|
|
392
|
+
{ name: '更新测试', method: 'test_update' },
|
|
393
|
+
{ name: '删除测试', method: 'test_delete' },
|
|
394
|
+
{ name: '事务测试', method: 'test_transaction' },
|
|
395
|
+
{ name: '连接池测试', method: 'test_connection_pool' },
|
|
396
|
+
{ name: '错误处理测试', method: 'test_error_handling' }
|
|
397
|
+
];
|
|
398
|
+
|
|
399
|
+
// 顺序执行测试用例
|
|
400
|
+
for (const test_case of test_cases) {
|
|
401
|
+
try {
|
|
402
|
+
await this[test_case.method]();
|
|
403
|
+
} catch (error) {
|
|
404
|
+
this._record_result(test_case.name, false, `测试执行异常: ${error.message}`);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// 添加短暂延迟,避免数据库压力
|
|
408
|
+
await this._sleep(100);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// 清理测试环境
|
|
412
|
+
await this._cleanup();
|
|
413
|
+
|
|
414
|
+
// 关闭数据库连接
|
|
415
|
+
if (this._mysql) {
|
|
416
|
+
await this._mysql.close();
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
console.log('\n=== 测试完成 ===\n');
|
|
420
|
+
return this._get_test_summary();
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* 获取测试摘要
|
|
425
|
+
* @returns {Object}
|
|
426
|
+
*/
|
|
427
|
+
TestMysql.prototype._get_test_summary = function() {
|
|
428
|
+
const total = this._test_results.length;
|
|
429
|
+
const passed = this._test_results.filter(r => r.success).length;
|
|
430
|
+
const failed = total - passed;
|
|
431
|
+
|
|
432
|
+
console.log(`测试摘要:`);
|
|
433
|
+
console.log(`总测试数: ${total}`);
|
|
434
|
+
console.log(`通过: ${passed}`);
|
|
435
|
+
console.log(`失败: ${failed}`);
|
|
436
|
+
console.log(`通过率: ${((passed / total) * 100).toFixed(1)}%`);
|
|
437
|
+
|
|
438
|
+
// 显示失败的测试
|
|
439
|
+
const failed_tests = this._test_results.filter(r => !r.success);
|
|
440
|
+
if (failed_tests.length > 0) {
|
|
441
|
+
console.log('\n失败的测试:');
|
|
442
|
+
failed_tests.forEach(test => {
|
|
443
|
+
console.log(` ✗ ${test.test_name}: ${test.message}`);
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return {
|
|
448
|
+
total,
|
|
449
|
+
passed,
|
|
450
|
+
failed,
|
|
451
|
+
results: this._test_results
|
|
452
|
+
};
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* 休眠函数
|
|
457
|
+
* @param {Number} ms - 毫秒数
|
|
458
|
+
* @returns {Promise}
|
|
459
|
+
*/
|
|
460
|
+
TestMysql.prototype._sleep = function(ms) {
|
|
461
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* 主测试函数
|
|
466
|
+
*/
|
|
467
|
+
TestMysql.prototype.main = async function() {
|
|
468
|
+
try {
|
|
469
|
+
const summary = await this.run_all_tests();
|
|
470
|
+
|
|
471
|
+
if (summary.failed > 0) {
|
|
472
|
+
console.log('\n❌ 部分测试失败,请检查数据库配置和连接');
|
|
473
|
+
process.exit(1);
|
|
474
|
+
} else {
|
|
475
|
+
console.log('\n✅ 所有测试通过!');
|
|
476
|
+
process.exit(0);
|
|
477
|
+
}
|
|
478
|
+
} catch (error) {
|
|
479
|
+
console.error('测试执行异常:', error);
|
|
480
|
+
process.exit(1);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
// 模块导出
|
|
485
|
+
exports.TestMysql = TestMysql;
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* 快速测试函数
|
|
489
|
+
* @param {Object} config - 数据库配置
|
|
490
|
+
*/
|
|
491
|
+
const quick_test = async function(config) {
|
|
492
|
+
const tester = new TestMysql(config);
|
|
493
|
+
await tester.main();
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
// 如果直接运行此文件,执行测试
|
|
497
|
+
if (require.main === module) {
|
|
498
|
+
// 从环境变量或默认配置获取数据库连接信息
|
|
499
|
+
const test_config = {
|
|
500
|
+
host: process.env.DB_HOST || '127.0.0.1',
|
|
501
|
+
port: parseInt(process.env.DB_PORT) || 3306,
|
|
502
|
+
user: process.env.DB_USER || 'root',
|
|
503
|
+
password: process.env.DB_PASSWORD || 'Asd159357',
|
|
504
|
+
database: process.env.DB_NAME || 'test_db',
|
|
505
|
+
debug: process.env.DEBUG === 'true',
|
|
506
|
+
connectionLimit: parseInt(process.env.DB_CONNECTION_LIMIT) || 5
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
console.log('使用配置:', {
|
|
510
|
+
...test_config,
|
|
511
|
+
password: '***' // 隐藏密码
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
quick_test(test_config);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// 导出快速测试函数
|
|
518
|
+
exports.quick_test = quick_test;
|