测试在 JavaScript 中的应用:单元测试、集成测试和端到端测试
测试是开发高质量软件不可或缺的组成部分。在 JavaScript 世界(尤其是在 Node.js 生态系统中),主要有三个测试级别:单元测试、集成测试和端到端测试。每种测试都有其特定的任务,并在开发的不同阶段使用。在本文中,我们将分析每种类型,展示代码示例并给出实用建议。
1. 单元测试
单元测试用于检查独立的、隔离的代码单元——函数、方法或类。主要目标是确保每个"单元"在独立于系统其他部分的情况下能正确工作。在 Node.js 中,最常使用 Jest 或 Mocha 框架配合 Chai 来实现。
Jest 的单元测试示例
假设我们有一个简单的折扣计算函数:
// discount.jsfunction calculateDiscount(price, percent) { if (typeof price !== 'number' || typeof percent !== 'number') { throw new Error('Both arguments must be numbers'); } if (price < 0 || percent < 0 || percent > 100) { throw new Error('Invalid values'); } return price - (price * percent / 100);}
module.exports = calculateDiscount;此函数的测试代码:
// discount.test.jsconst calculateDiscount = require('./discount');
describe('calculateDiscount', () => { test('correctly calculates 10% discount from 1000', () => { expect(calculateDiscount(1000, 10)).toBe(900); });
test('returns 0 at 100% discount', () => { expect(calculateDiscount(500, 100)).toBe(0); });
test('throws an error with a negative price', () => { expect(() => calculateDiscount(-100, 10)).toThrow('Invalid values'); });
test('throws an error with non-numeric arguments', () => { expect(() => calculateDiscount('100', 10)).toThrow('Both arguments must be numbers'); });});- 优点:执行速度快,易于编写,能精确定位有问题的模块。
- 缺点:无法检查组件之间的交互。
- 适用场景:用于业务逻辑函数、工具函数和验证器。
2. 集成测试
集成测试用于检查不同模块或服务如何协同工作。例如,与数据库、外部 API 或文件系统的交互。在 Node.js 中,这类测试常使用 Supertest(用于 HTTP 请求)和 Jest。
Express 应用的集成测试示例
假设我们有一个简单的 Express 服务器,其中包含一个创建用户的端点:
// server.jsconst express = require('express');const app = express();app.use(express.json());
const users = [];
app.post('/users', (req, res) => { const { name, email } = req.body; if (!name || !email) { return res.status(400).json({ error: 'Name and email are required' }); } const user = { id: users.length + 1, name, email }; users.push(user); res.status(201).json(user);});
module.exports = app;使用 Supertest 进行集成测试:
// server.test.jsconst request = require('supertest');const app = require('./server');
describe('POST /users', () => { test('creates a new user with valid data', async () => { const response = await request(app) .post('/users') .send({ name: 'Ivan', email: 'ivan@example.com' });
expect(response.statusCode).toBe(201); expect(response.body).toHaveProperty('id'); expect(response.bo