Node.js 测试策略与微服务架构

Node.js 测试金字塔实践:单元测试(Jest/Mocha)、集成测试(Supertest)、E2E 测试(Playwright),以及微服务拆分、gRPC/消息队列通信与服务发现。

1. 测试金字塔

        /
       / E2E 测试       ← 少而精,覆盖核心用户路径
      /_________________/
     /  集成测试         ← 测试模块间交互
    /_________________/
   /   单元测试          ← 大量、快速、独立
  /_________________/
类型比例速度工具
单元测试70%< 100msJest、Vitest
集成测试20%< 1sSupertest + Test DB
E2E 测试10%< 10sPlaywright、Cypress

2. 单元测试(Jest)

// utils.test.js
const { sum, asyncFetch } = require('./utils');

describe('utils', () => {
    beforeEach(() => {
        // 每个测试前执行
    });

    test('sum adds numbers', () => {
        expect(sum(1, 2)).toBe(3);
        expect(sum(-1, 1)).toBe(0);
    });

    test('async fetch', async () => {
        const data = await asyncFetch('https://api.example.com');
        expect(data).toHaveProperty('id');
    });

    // Mock
    test('with mocked dependency', () => {
        const mockFn = jest.fn().mockReturnValue('mocked');
        expect(mockFn()).toBe('mocked');
        expect(mockFn).toHaveBeenCalledTimes(1);
    });
});

// 覆盖率
// npx jest --coverage

3. 集成测试

// app.test.js
const request = require('supertest');
const app = require('./app');

describe('API Integration', () => {
    beforeAll(async () => {
        await setupTestDatabase();
    });

    afterAll(async () => {
        await teardownTestDatabase();
    });

    test('GET /users returns users', async () => {
        const res = await request(app).get('/users');
        expect(res.status).toBe(200);
        expect(res.body).toBeInstanceOf(Array);
    });

    test('POST /users creates user', async () => {
        const res = await request(app)
            .post('/users')
            .send({ email: 'test@example.com', name: 'Test' });
        expect(res.status).toBe(201);
        expect(res.body.email).toBe('test@example.com');
    });
});

4. 微服务通信

4.1 gRPC

// user.proto
syntax = "proto3";

service UserService {
    rpc GetUser (GetUserRequest) returns (User);
    rpc ListUsers (ListUsersRequest) returns (stream User);
}

message GetUserRequest { string id = 1; }
message User { string id = 1; string name = 2; string email = 3; }
// gRPC 客户端
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const packageDef = protoLoader.loadSync('user.proto');
const grpcObject = grpc.loadPackageDefinition(packageDef);
const client = new grpcObject.UserService('localhost:50051', grpc.credentials.createInsecure());

client.getUser({ id: '123' }, (err, response) => {
    console.log(response);
});

4.2 消息队列(RabbitMQ)

const amqp = require('amqplib');

// 生产者
const conn = await amqp.connect('amqp://localhost');
const ch = await conn.createChannel();
await ch.assertQueue('orders');
ch.sendToQueue('orders', Buffer.from(JSON.stringify({ orderId: '123' })));

// 消费者
await ch.consume('orders', (msg) => {
    const order = JSON.parse(msg.content.toString());
    processOrder(order);
    ch.ack(msg);
});

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「nodejs」更多文章

  1. Node.js ORM 深度对比:Prisma、TypeORM、Sequelize 与 Drizzle
  2. Node.js 设计模式与最佳实践:从 SOLID 到六边形架构
  3. Node.js 高级测试策略:从单元测试到混沌工程的完整实践