import http from 'http' const BASE_URL = 'http://localhost:3001' // 测试结果收集 const testResults = { passed: 0, failed: 0, tests: [] } // HTTP请求辅助函数 function request(method, path, data = null) { return new Promise((resolve, reject) => { const url = new URL(path, BASE_URL) const options = { method, headers: { 'Content-Type': 'application/json' } } const req = http.request(url, options, (res) => { let body = '' res.on('data', (chunk) => { body += chunk }) res.on('end', () => { try { const response = JSON.parse(body) resolve({ status: res.statusCode, data: response }) } catch (e) { resolve({ status: res.statusCode, data: body }) } }) }) req.on('error', reject) if (data) { req.write(JSON.stringify(data)) } req.end() }) } // 断言函数 function assert(condition, testName, message = '') { const result = { name: testName, passed: condition, message: message || (condition ? '通过' : '失败') } testResults.tests.push(result) if (condition) { testResults.passed++ console.log(`✅ ${testName}`) } else { testResults.failed++ console.log(`❌ ${testName}: ${message}`) } } // 检查响应格式 function checkResponseFormat(response, testNamePrefix) { assert( response.data.hasOwnProperty('success'), `${testNamePrefix} - 响应包含success字段`, `响应缺少success字段,实际响应: ${JSON.stringify(response.data)}` ) assert( response.data.hasOwnProperty('data'), `${testNamePrefix} - 响应包含data字段`, `响应缺少data字段,实际响应: ${JSON.stringify(response.data)}` ) assert( response.data.hasOwnProperty('message'), `${testNamePrefix} - 响应包含message字段`, `响应缺少message字段,实际响应: ${JSON.stringify(response.data)}` ) } // 主测试流程 async function runTests() { console.log('='.repeat(60)) console.log('个人理财系统 - API集成测试') console.log('='.repeat(60)) try { // 1. 健康检查 console.log('\n【1】健康检查测试') console.log('-'.repeat(40)) const healthRes = await request('GET', '/health') assert(healthRes.status === 200, '健康检查状态码200') checkResponseFormat(healthRes, '健康检查') assert(healthRes.data.success === true, '健康检查success为true') // 2. 基础API信息 console.log('\n【2】API基础信息测试') console.log('-'.repeat(40)) const apiRes = await request('GET', '/api') assert(apiRes.status === 200, 'API信息状态码200') checkResponseFormat(apiRes, 'API信息') // 3. 用户接口测试 console.log('\n【3】用户接口测试') console.log('-'.repeat(40)) // 创建测试用户 const createUserRes = await request('POST', '/api/users', { name: '测试用户', email: 'test' + Date.now() + '@example.com' }) assert(createUserRes.status === 200, '创建用户状态码200') checkResponseFormat(createUserRes, '创建用户') assert(createUserRes.data.success === true, '创建用户success为true') assert(createUserRes.data.data !== null, '创建用户返回数据不为null') assert(createUserRes.data.data.id !== undefined, '创建用户返回ID') const testUserId = createUserRes.data.data.id // 获取用户列表 const getUsersRes = await request('GET', '/api/users') assert(getUsersRes.status === 200, '获取用户列表状态码200') checkResponseFormat(getUsersRes, '获取用户列表') assert(Array.isArray(getUsersRes.data.data), '用户列表为数组') // 4. 账户接口测试 console.log('\n【4】账户接口测试') console.log('-'.repeat(40)) // 创建账户 const createAccountRes = await request('POST', '/api/accounts', { userId: testUserId, name: '测试账户', type: 'cash', balance: 1000 }) assert(createAccountRes.status === 200, '创建账户状态码200') checkResponseFormat(createAccountRes, '创建账户') assert(createAccountRes.data.success === true, '创建账户success为true') assert(createAccountRes.data.data !== null, '创建账户返回数据不为null') const testAccountId = createAccountRes.data.data.id // 获取账户列表 const getAccountsRes = await request('GET', `/api/accounts?userId=${testUserId}`) assert(getAccountsRes.status === 200, '获取账户列表状态码200') checkResponseFormat(getAccountsRes, '获取账户列表') assert(Array.isArray(getAccountsRes.data.data), '账户列表为数组') // 获取单个账户 const getAccountRes = await request('GET', `/api/accounts/${testAccountId}`) assert(getAccountRes.status === 200, '获取单个账户状态码200') checkResponseFormat(getAccountRes, '获取单个账户') assert(getAccountRes.data.data.id === testAccountId, '账户ID匹配') // 更新账户 const updateAccountRes = await request('PUT', `/api/accounts/${testAccountId}`, { name: '测试账户(已更新)', balance: 2000 }) assert(updateAccountRes.status === 200, '更新账户状态码200') checkResponseFormat(updateAccountRes, '更新账户') assert(updateAccountRes.data.data.name === '测试账户(已更新)', '账户名称已更新') // 5. 交易记录接口测试 console.log('\n【5】交易记录接口测试') console.log('-'.repeat(40)) // 创建收入记录 const createIncomeRes = await request('POST', '/api/records', { userId: testUserId, accountId: testAccountId, type: 'income', amount: 500, category: '工资', description: '测试收入' }) assert(createIncomeRes.status === 200, '创建收入记录状态码200') checkResponseFormat(createIncomeRes, '创建收入记录') assert(createIncomeRes.data.success === true, '创建收入记录success为true') const testRecordId = createIncomeRes.data.data.id // 创建支出记录 const createExpenseRes = await request('POST', '/api/records', { userId: testUserId, accountId: testAccountId, type: 'expense', amount: 200, category: '餐饮', description: '测试支出' }) assert(createExpenseRes.status === 200, '创建支出记录状态码200') checkResponseFormat(createExpenseRes, '创建支出记录') // 获取记录列表 const getRecordsRes = await request('GET', `/api/records?userId=${testUserId}`) assert(getRecordsRes.status === 200, '获取记录列表状态码200') checkResponseFormat(getRecordsRes, '获取记录列表') assert(Array.isArray(getRecordsRes.data.data), '记录列表为数组') // 获取单个记录 const getRecordRes = await request('GET', `/api/records/${testRecordId}`) assert(getRecordRes.status === 200, '获取单个记录状态码200') checkResponseFormat(getRecordRes, '获取单个记录') // 更新记录 const updateRecordRes = await request('PUT', `/api/records/${testRecordId}`, { description: '测试收入(已更新)' }) assert(updateRecordRes.status === 200, '更新记录状态码200') checkResponseFormat(updateRecordRes, '更新记录') // 6. 预算接口测试 console.log('\n【6】预算接口测试') console.log('-'.repeat(40)) const currentMonth = new Date().toISOString().slice(0, 7) // 创建预算 const createBudgetRes = await request('POST', '/api/budgets', { userId: testUserId, category: '餐饮', amount: 1000, month: currentMonth }) assert(createBudgetRes.status === 200, '创建预算状态码200') checkResponseFormat(createBudgetRes, '创建预算') assert(createBudgetRes.data.success === true, '创建预算success为true') const testBudgetId = createBudgetRes.data.data.id // 获取预算列表 const getBudgetsRes = await request('GET', `/api/budgets?userId=${testUserId}`) assert(getBudgetsRes.status === 200, '获取预算列表状态码200') checkResponseFormat(getBudgetsRes, '获取预算列表') assert(Array.isArray(getBudgetsRes.data.data), '预算列表为数组') // 获取单个预算 const getBudgetRes = await request('GET', `/api/budgets/${testBudgetId}`) assert(getBudgetRes.status === 200, '获取单个预算状态码200') checkResponseFormat(getBudgetRes, '获取单个预算') // 更新预算 const updateBudgetRes = await request('PUT', `/api/budgets/${testBudgetId}`, { amount: 1500 }) assert(updateBudgetRes.status === 200, '更新预算状态码200') checkResponseFormat(updateBudgetRes, '更新预算') // 7. 统计接口测试 console.log('\n【7】统计接口测试') console.log('-'.repeat(40)) // 月度统计 const monthlyStatsRes = await request('GET', `/api/statistics/monthly?userId=${testUserId}&month=${currentMonth}`) assert(monthlyStatsRes.status === 200, '月度统计状态码200') checkResponseFormat(monthlyStatsRes, '月度统计') assert(monthlyStatsRes.data.data.totalIncome !== undefined, '月度统计包含总收入') assert(monthlyStatsRes.data.data.totalExpense !== undefined, '月度统计包含总支出') // 趋势统计 const trendRes = await request('GET', `/api/statistics/trend?userId=${testUserId}`) assert(trendRes.status === 200, '趋势统计状态码200') checkResponseFormat(trendRes, '趋势统计') assert(Array.isArray(trendRes.data.data), '趋势统计返回数组') // 8. 仪表盘接口测试 console.log('\n【8】仪表盘接口测试') console.log('-'.repeat(40)) const dashboardRes = await request('GET', `/api/dashboard/summary?userId=${testUserId}`) assert(dashboardRes.status === 200, '仪表盘状态码200') checkResponseFormat(dashboardRes, '仪表盘') assert(dashboardRes.data.data.totalBalance !== undefined, '仪表盘包含总余额') assert(dashboardRes.data.data.monthIncome !== undefined, '仪表盘包含本月收入') assert(dashboardRes.data.data.monthExpense !== undefined, '仪表盘包含本月支出') // 9. 清理测试数据 console.log('\n【9】清理测试数据') console.log('-'.repeat(40)) // 删除记录 await request('DELETE', `/api/records/${testRecordId}`) // 删除预算 await request('DELETE', `/api/budgets/${testBudgetId}`) // 删除账户 await request('DELETE', `/api/accounts/${testAccountId}`) console.log('✅ 测试数据清理完成') } catch (error) { console.error('❌ 测试过程出错:', error) } // 输出测试报告 console.log('\n' + '='.repeat(60)) console.log('测试报告摘要') console.log('='.repeat(60)) console.log(`总测试数: ${testResults.tests.length}`) console.log(`✅ 通过: ${testResults.passed}`) console.log(`❌ 失败: ${testResults.failed}`) console.log(`通过率: ${((testResults.passed / testResults.tests.length) * 100).toFixed(1)}%`) console.log('='.repeat(60)) return testResults } // 运行测试 runTests().then(results => { process.exit(results.failed > 0 ? 1 : 0) })