Skill545 repo starsupdated 9d ago
backend/testing-guide
This Claude Code skill provides a comprehensive backend testing guide covering unit tests, integration tests, and end-to-end tests with specific implementation patterns. Use this when developers need structured guidance on writing backend tests following the testing pyramid approach, including Service layer tests with mocked repositories, business logic validation, and complete API flow verification required before QA validation.
Install in Claude Code
Copygit clone --depth 1 https://github.com/echoVic/boss-skill /tmp/backend-testing-guide && cp -r /tmp/backend-testing-guide/skill/skills/backend/testing-guide ~/.claude/skills/backend-testing-guideThen start a new Claude Code session; the skill loads automatically.
Definition
SKILL.md
# 后端测试编写指南
## 测试要求(强制)
> **职责边界**:Backend Agent 是测试的**编写者**,QA Agent 是测试的**验证者**。
### 测试金字塔
| 测试类型 | 占比 | 要求 |
|----------|------|------|
| **单元测试** | ~70% | Service 层、业务逻辑必须有测试 |
| **集成测试** | ~20% | API 端点、数据库操作测试 |
| **E2E 测试** | ~10% | **必须编写**,完整 API 流程测试 |
## 单元测试编写
### Service 层测试
```typescript
// services/userService.test.ts
import { UserService } from './userService';
import { UserRepository } from '../repositories/userRepository';
jest.mock('../repositories/userRepository');
describe('UserService', () => {
let userService: UserService;
let userRepository: jest.Mocked<UserRepository>;
beforeEach(() => {
userRepository = new UserRepository() as jest.Mocked<UserRepository>;
userService = new UserService(userRepository);
});
describe('getById', () => {
it('returns user when found', async () => {
const mockUser = { id: '1', name: 'Alice', email: 'alice@example.com' };
userRepository.findById.mockResolvedValue(mockUser);
const result = await userService.getById('1');
expect(result).toEqual(mockUser);
expect(userRepository.findById).toHaveBeenCalledWith('1');
});
it('throws NotFoundError when user not found', async () => {
userRepository.findById.mockResolvedValue(null);
await expect(userService.getById('999')).rejects.toThrow('User not found');
});
});
describe('create', () => {
it('creates user with valid data', async () => {
const createData = { name: 'Bob', email: 'bob@example.com' };
const mockUser = { id: '2', ...createData };
userRepository.findByEmail.mockResolvedValue(null);
userRepository.create.mockResolvedValue(mockUser);
const result = await userService.create(createData);
expect(result).toEqual(mockUser);
expect(userRepository.findByEmail).toHaveBeenCalledWith('bob@example.com');
expect(userRepository.create).toHaveBeenCalledWith(createData);
});
it('throws ConflictError when email already exists', async () => {
const createData = { name: 'Bob', email: 'existing@example.com' };
userRepository.findByEmail.mockResolvedValue({ id: '1', name: 'Existing', email: 'existing@example.com' });
await expect(userService.create(createData)).rejects.toThrow('Email already exists');
});
});
});
```
### 业务逻辑测试
```typescript
// services/orderService.test.ts
describe('OrderService', () => {
describe('calculateTotal', () => {
it('calculates total with discount', () => {
const items = [
{ price: 100, quantity: 2 },
{ price: 50, quantity: 1 },
];
const discount = 0.1; // 10% off
const total = orderService.calculateTotal(items, discount);
expect(total).toBe(225); // (200 + 50) * 0.9
});
it('handles zero discount', () => {
const items = [{ price: 100, quantity: 1 }];
const total = orderService.calculateTotal(items, 0);
expect(total).toBe(100);
});
});
describe('validateOrder', () => {
it('validates order with sufficient stock', async () => {
const order = { productId: '1', quantity: 5 };
productRepository.findById.mockResolvedValue({ id: '1', stock: 10 });
const result = await orderService.validateOrder(order);
expect(result.valid).toBe(true);
});
it('rejects order with insufficient stock', async () => {
const order = { productId: '1', quantity: 15 };
productRepository.findById.mockResolvedValue({ id: '1', stock: 10 });
const result = await orderService.validateOrder(order);
expect(result.valid).toBe(false);
expect(result.error).toBe('Insufficient stock');
});
});
});
```
## 集成测试编写
### API 端点测试
```typescript
// controllers/userController.test.ts
import request from 'supertest';
import { app } from '../app';
import { db } from '../db';
describe('User API', () => {
beforeEach(async () => {
// 清理测试数据库
await db.user.deleteMany();
});
afterAll(async () => {
await db.$disconnect();
});
describe('POST /api/users', () => {
it('creates a new user', async () => {
const userData = {
name: 'Alice',
email: 'alice@example.com',
};
const response = await request(app)
.post('/api/users')
.send(userData)
.expect(201);
expect(response.body.success).toBe(true);
expect(response.body.data).toMatchObject(userData);
expect(response.body.data.id).toBeDefined();
});
it('returns 400 for invalid email', async () => {
const userData = {
name: 'Bob',
email: 'invalid-email',
};
const response = await request(app)
.post('/api/users')
.send(userData)
.expect(400);
expect(response.body.success).toBe(false);
expect(response.body.error.code).toBe('VALIDATION_ERROR');
});
it('returns 409 for duplicate email', async () => {
const userData = {
name: 'Charlie',
email: 'duplicate@example.com',
};
// 创建第一个用户
await request(app).post('/api/users').send(userData);
// 尝试创建重复邮箱的用户
const response = await request(app)
.post('/api/users')
.send(userData)
.expect(409);
expect(response.body.error.code).toBe('CONFLICT');
});
});
describe('GET /api/users/:id', () => {
it('returns user by id', async () => {
// 创建测试用户
const createResponse = await request(app)
.post('/api/users')
.send({ name: 'Dave', email: 'dave@example.com' });
const userId = createResponse.body.data.id;
// 获取用户
const response = await request(app)
.get(`/api/users/${userId}`)
.expect(200);
expect(response.body.data.id).toBe(userId);
expect(response.body.data.name).toBe('Dave');
});
it('returns 404 for non-existent user', async () => {
const response = await request(app)
.get('/api/users/non-existent-id')
.expect(404);
exMore from this repository
bossSkill
|
architect/architecture-designSkill
系统架构设计方法论,包含架构模式选择、系统分层、目录结构设计
architect/data-api-designSkill
数据模型和API设计方法论,包含ERD设计、数据字典、RESTful API规范
architect/tech-researchSkill
技术调研方法论,通过系统性调研和对比分析,为技术选型提供数据支持
backend/api-developmentSkill
后端API开发方法论,包括RESTful/GraphQL设计、请求验证、错误处理和安全实现
brainstormingSkill
|
devops/changelog-generationSkill
自动生成 CHANGELOG,基于 git 提交历史和 pipeline 产物信息,遵循 Conventional Commits 和 Keep a Changelog 规范
devops/deployment-processSkill
部署流程和CI/CD配置,确保安全可靠的部署