引言
单元测试是保证代码质量的基石,但编写测试用例往往耗时且繁琐。本文将展示如何利用 AtomCode 的智能能力,实现从代码分析到测试用例自动生成的全流程,大幅提升测试效率。
一、单元测试现状与痛点
1.1 传统测试开发的挑战
typescript
interface TestingChallenges {
// 测试编写效率问题
efficiency: {
timeConsuming: '编写测试时间占开发时间 30-50%',
repetitiveWork: '大量重复的测试模板',
highMaintenance: '代码变更需要同步更新测试'
};
// 测试覆盖率问题
coverage: {
blindSpots: '难以覆盖所有边界条件',
edgeCases: '边界条件测试容易遗漏',
complexLogic: '复杂业务逻辑难以测试'
};
// 测试质量问题
quality: {
brittleTests: '测试用例过于脆弱',
falsePositives: '误报导致信任度下降',
lackOfIsolation: '测试间相互依赖'
};
}
1.2 AI 测试生成的优势
typescript
interface AITestingAdvantages {
capabilities: [
{
name: '代码理解',
description: '理解业务逻辑和代码结构',
benefit: '生成准确的测试用例'
},
{
name: '边界条件识别',
description: '自动识别边界和异常场景',
benefit: '提高测试覆盖率'
},
{
name: '测试模板生成',
description: '生成完整的测试框架和模板',
benefit: '减少重复工作'
},
{
name: '测试优化',
description: '优化测试结构和断言',
benefit: '提高测试质量'
}
];
}
二、智能测试分析
2.1 代码结构分析
typescript
class TestAnalyzer {
// 分析函数结构
async analyzeFunction(func: Function): Promise<FunctionAnalysis> {
const prompt = `
请分析以下函数,为生成单元测试提供信息:
函数代码:
${func.toString()}
分析要求:
1. 函数签名和参数类型
2. 返回值类型和可能的返回值
3. 依赖关系(外部函数、模块、数据库)
4. 分支条件和边界情况
5. 可能抛出的异常
6. 副作用(状态改变、I/O操作)
请输出结构化的分析结果。
`;
const result = await atomCode.analyze(prompt);
return this.parseFunctionAnalysis(result);
}
// 分析类结构
async analyzeClass(cls: Class): Promise<ClassAnalysis> {
const prompt = `
请分析以下类,为生成单元测试提供信息:
类代码:
${cls.toString()}
分析要求:
1. 类的公共接口
2. 构造函数依赖
3. 成员变量及其初始状态
4. 方法之间的调用关系
5. 需要 Mock 的外部依赖
6. 状态转换路径
请输出结构化的分析结果。
`;
const result = await atomCode.analyze(prompt);
return this.parseClassAnalysis(result);
}
// 识别测试场景
async identifyTestScenarios(code: string): Promise<TestScenario[]> {
const prompt = `
请识别以下代码的测试场景:
代码:
${code}
需要识别:
1. 正常流程测试场景
2. 边界条件测试场景
3. 异常处理测试场景
4. 性能测试场景(可选)
为每个场景提供:
- 场景描述
- 输入条件
- 预期输出
- 前置条件
- 后置条件
`;
const result = await atomCode.analyze(prompt);
return this.parseTestScenarios(result);
}
}
2.2 测试覆盖率分析
typescript
class CoverageAnalyzer {
// 分析测试覆盖率缺口
async analyzeCoverageGaps(code: string, existingTests: Test[]): Promise<CoverageGap[]> {
const prompt = `
请分析以下代码和现有测试,识别测试覆盖率缺口:
代码:
${code}
现有测试:
${existingTests.map(t => t.toString()).join('\n')}
分析要求:
1. 当前测试覆盖率估算
2. 未覆盖的代码路径
3. 未测试的分支条件
4. 未覆盖的边界情况
5. 建议新增的测试用例
请输出详细的覆盖率分析报告。
`;
const result = await atomCode.analyze(prompt);
return this.parseCoverageGaps(result);
}
// 生成测试覆盖率报告
async generateCoverageReport(module: Module): Promise<CoverageReport> {
return {
moduleName: module.name,
totalLines: module.lineCount,
coveredLines: this.calculateCoveredLines(module),
coveragePercentage: this.calculateCoverage(module),
gaps: await this.analyzeCoverageGaps(module.code, module.tests),
recommendations: this.generateRecommendations(module)
};
}
}
三、测试用例自动生成
3.1 基础测试用例生成
typescript
class TestCaseGenerator {
// 生成函数测试用例
async generateFunctionTests(func: Function): Promise<TestCases> {
const prompt = `
请为以下函数生成完整的单元测试用例:
函数代码:
${func.toString()}
测试要求:
1. 使用 ${this.getTestingFramework()} 框架
2. 覆盖所有正常流程
3. 覆盖边界条件
4. 覆盖异常情况
5. 使用适当的断言
6. 添加测试注释说明
请输出完整的测试代码。
`;
const result = await atomCode.generate(prompt);
return this.parseTestCases(result);
}
// 生成类测试用例
async generateClassTests(cls: Class): Promise<TestCases> {
const prompt = `
请为以下类生成完整的单元测试用例:
类代码:
${cls.toString()}
测试要求:
1. 使用 ${this.getTestingFramework()} 框架
2. Mock 所有外部依赖
3. 测试所有公共方法
4. 测试状态转换
5. 测试边界条件和异常
6. 提供测试数据
请输出完整的测试代码。
`;
const result = await atomCode.generate(prompt);
return this.parseTestCases(result);
}
// 生成 Mock 代码
async generateMocks(dependencies: Dependency[]): Promise<MockCode> {
const prompt = `
请为以下依赖生成 Mock 对象:
依赖列表:
${dependencies.map(d => `${d.name}: ${d.type}`).join('\n')}
Mock 要求:
1. 使用 ${this.getMockLibrary()}
2. 模拟正常返回值
3. 模拟异常情况
4. 支持断言调用次数和参数
5. 提供默认实现
请输出完整的 Mock 代码。
`;
const result = await atomCode.generate(prompt);
return this.parseMockCode(result);
}
}
3.2 实战测试生成示例
typescript
class UserServiceTestGenerator {
// 用户服务测试生成
async generateUserServiceTests(): Promise<GeneratedTests> {
const serviceCode = `
class UserService {
constructor(private userRepository: UserRepository) {}
async createUser(userData: CreateUserDto): Promise<User> {
// 验证输入
if (!userData.email || !userData.password) {
throw new ValidationError('Email and password are required');
}
// 检查用户是否已存在
const existingUser = await this.userRepository.findByEmail(userData.email);
if (existingUser) {
throw new ConflictError('Email already exists');
}
// 创建用户
const user = await this.userRepository.create({
...userData,
password: await this.hashPassword(userData.password)
});
// 发送欢迎邮件
await this.sendWelcomeEmail(user);
return user;
}
async getUserById(id: string): Promise<User | null> {
if (!id || id.length !== 36) {
throw new ValidationError('Invalid user ID');
}
return this.userRepository.findById(id);
}
}
`;
const testPrompt = `
请为以下用户服务类生成完整的单元测试:
服务代码:
${serviceCode}
测试框架:Jest
Mock 库:Jest Mock
需要测试的场景:
1. createUser - 正常创建用户
2. createUser - 缺少邮箱或密码
3. createUser - 邮箱已存在
4. getUserById - 正常获取用户
5. getUserById - 无效用户ID
6. getUserById - 用户不存在
请提供:
1. 完整的测试文件
2. Mock 配置
3. 测试数据
4. 断言验证
`;
const result = await atomCode.generate(testPrompt);
return this.parseGeneratedTests(result);
}
}
3.3 生成的测试代码示例
typescript
// Jest 测试文件 - 由 AtomCode 生成
describe('UserService', () => {
let userService: UserService;
let mockUserRepository: jest.Mocked<UserRepository>;
let mockEmailService: jest.Mocked<EmailService>;
beforeEach(() => {
// Mock 依赖注入
mockUserRepository = {
findByEmail: jest.fn(),
findById: jest.fn(),
create: jest.fn()
};
mockEmailService = {
sendWelcomeEmail: jest.fn()
};
userService = new UserService(mockUserRepository, mockEmailService);
});
describe('createUser', () => {
it('should create user successfully when valid data provided', async () => {
// Arrange
const mockUser = { id: '123', email: 'test@example.com' };
const createUserDto = { email: 'test@example.com', password: 'password123' };
mockUserRepository.findByEmail.mockResolvedValue(null);
mockUserRepository.create.mockResolvedValue(mockUser);
mockEmailService.sendWelcomeEmail.mockResolvedValue();
// Act
const result = await userService.createUser(createUserDto);
// Assert
expect(mockUserRepository.findByEmail).toHaveBeenCalledWith('test@example.com');
expect(mockUserRepository.create).toHaveBeenCalledWith(expect.objectContaining({
email: 'test@example.com'
}));
expect(mockEmailService.sendWelcomeEmail).toHaveBeenCalledWith(mockUser);
expect(result).toEqual(mockUser);
});
it('should throw ValidationError when email is missing', async () => {
// Arrange
const createUserDto = { email: '', password: 'password123' };
// Act & Assert
await expect(userService.createUser(createUserDto))
.rejects
.toThrow(new ValidationError('Email and password are required'));
});
it('should throw ConflictError when email already exists', async () => {
// Arrange
const existingUser = { id: '123', email: 'test@example.com' };
const createUserDto = { email: 'test@example.com', password: 'password123' };
mockUserRepository.findByEmail.mockResolvedValue(existingUser);
// Act & Assert
await expect(userService.createUser(createUserDto))
.rejects
.toThrow(new ConflictError('Email already exists'));
});
});
describe('getUserById', () => {
it('should return user when valid ID provided', async () => {
// Arrange
const mockUser = { id: '123e4567-e89b-12d3-a456-426614174000', email: 'test@example.com' };
mockUserRepository.findById.mockResolvedValue(mockUser);
// Act
const result = await userService.getUserById(mockUser.id);
// Assert
expect(mockUserRepository.findById).toHaveBeenCalledWith(mockUser.id);
expect(result).toEqual(mockUser);
});
it('should throw ValidationError when invalid ID provided', async () => {
// Arrange
const invalidId = 'invalid-id';
// Act & Assert
await expect(userService.getUserById(invalidId))
.rejects
.toThrow(new ValidationError('Invalid user ID'));
});
it('should return null when user not found', async () => {
// Arrange
const validId = '123e4567-e89b-12d3-a456-426614174000';
mockUserRepository.findById.mockResolvedValue(null);
// Act
const result = await userService.getUserById(validId);
// Assert
expect(mockUserRepository.findById).toHaveBeenCalledWith(validId);
expect(result).toBeNull();
});
});
});
四、参数化测试与数据驱动
4.1 参数化测试生成
typescript
class ParameterizedTestGenerator {
// 生成参数化测试
async generateParameterizedTests(func: Function, testCases: TestCase[]): Promise<ParameterizedTestCode> {
const prompt = `
请为以下函数生成参数化测试:
函数代码:
${func.toString()}
测试用例数据:
${JSON.stringify(testCases)}
要求:
1. 使用 ${this.getTestingFramework()} 的参数化测试功能
2. 为每组测试数据生成独立的测试
3. 使用清晰的测试名称
4. 提供详细的断言
请输出完整的参数化测试代码。
`;
const result = await atomCode.generate(prompt);
return this.parseParameterizedTestCode(result);
}
// 生成测试数据
async generateTestData(func: Function): Promise<TestData[]> {
const prompt = `
请为以下函数生成测试数据:
函数代码:
${func.toString()}
测试数据要求:
1. 正常输入数据
2. 边界条件数据
3. 异常输入数据
4. 特殊场景数据
为每条测试数据提供:
- 输入值
- 预期输出
- 测试名称
- 前置条件
`;
const result = await atomCode.analyze(prompt);
return this.parseTestData(result);
}
}
4.2 参数化测试示例
typescript
// 参数化测试示例 - 由 AtomCode 生成
describe('EmailValidator', () => {
// 参数化测试数据
const testCases = [
{
name: 'valid email',
input: 'user@example.com',
expected: true
},
{
name: 'valid email with subdomain',
input: 'user@sub.example.com',
expected: true
},
{
name: 'valid email with numbers',
input: 'user123@example.com',
expected: true
},
{
name: 'invalid email - missing @',
input: 'userexample.com',
expected: false
},
{
name: 'invalid email - missing domain',
input: 'user@',
expected: false
},
{
name: 'invalid email - empty',
input: '',
expected: false
},
{
name: 'invalid email - spaces',
input: 'user @ example.com',
expected: false
},
{
name: 'invalid email - special characters',
input: 'user#@example.com',
expected: false
}
];
// 使用 Jest 的参数化测试
test.each(testCases)(
'should return $expected for $name',
({ input, expected }) => {
const result = EmailValidator.validate(input);
expect(result).toBe(expected);
}
);
});
// 另一种参数化测试风格
describe('PasswordValidator', () => {
const validPasswords = [
'Password123!',
'MyP@ssw0rd',
'S3cur3P@ss'
];
const invalidPasswords = [
{ password: 'short', reason: 'too short' },
{ password: 'alllowercase123', reason: 'no uppercase' },
{ password: 'ALLUPPERCASE123', reason: 'no lowercase' },
{ password: 'NoNumbers!', reason: 'no numbers' },
{ password: 'NoSpecialChar123', reason: 'no special characters' }
];
test.each(validPasswords)(
'should validate password: %s',
(password) => {
const result = PasswordValidator.validate(password);
expect(result.isValid).toBe(true);
}
);
test.each(invalidPasswords)(
'should invalidate password because $reason',
({ password }) => {
const result = PasswordValidator.validate(password);
expect(result.isValid).toBe(false);
}
);
});
五、集成测试与端到端测试
5.1 集成测试生成
typescript
class IntegrationTestGenerator {
// 生成集成测试
async generateIntegrationTests(services: Service[]): Promise<IntegrationTestCode> {
const prompt = `
请为以下服务生成集成测试:
服务列表:
${services.map(s => `${s.name}: ${s.description}`).join('\n')}
测试要求:
1. 测试服务间的协作
2. 测试数据库交互
3. 测试 API 调用链
4. 使用测试数据库
5. 清理测试数据
请输出完整的集成测试代码。
`;
const result = await atomCode.generate(prompt);
return this.parseIntegrationTestCode(result);
}
// 生成 API 测试
async generateAPITests(apiEndpoints: Endpoint[]): Promise<APITestCode> {
const prompt = `
请为以下 API 端点生成测试:
端点列表:
${apiEndpoints.map(e => `${e.method} ${e.path}`).join('\n')}
测试要求:
1. 使用 ${this.getAPITestingFramework()}
2. 测试正常响应
3. 测试错误响应
4. 测试认证授权
5. 测试边界条件
请输出完整的 API 测试代码。
`;
const result = await atomCode.generate(prompt);
return this.parseAPITestCode(result);
}
}
5.2 API 测试示例
typescript
// API 集成测试示例 - 由 AtomCode 生成
describe('User API', () => {
let app: Express;
let request: SuperTest.SuperTest<SuperTest.Test>;
beforeAll(async () => {
app = await createTestApp();
request = supertest(app);
});
beforeEach(async () => {
await clearTestDatabase();
});
describe('POST /api/users', () => {
it('should create user successfully', async () => {
const response = await request
.post('/api/users')
.send({
email: 'test@example.com',
password: 'password123',
name: 'Test User'
});
expect(response.status).toBe(201);
expect(response.body).toHaveProperty('id');
expect(response.body.email).toBe('test@example.com');
expect(response.body.name).toBe('Test User');
});
it('should return 400 when missing email', async () => {
const response = await request
.post('/api/users')
.send({
password: 'password123',
name: 'Test User'
});
expect(response.status).toBe(400);
expect(response.body.error).toBe('Email is required');
});
it('should return 409 when email already exists', async () => {
await request.post('/api/users').send({
email: 'test@example.com',
password: 'password123',
name: 'Test User'
});
const response = await request
.post('/api/users')
.send({
email: 'test@example.com',
password: 'password456',
name: 'Another User'
});
expect(response.status).toBe(409);
expect(response.body.error).toBe('Email already exists');
});
});
describe('GET /api/users/:id', () => {
it('should return user when valid ID provided', async () => {
const createResponse = await request
.post('/api/users')
.send({
email: 'test@example.com',
password: 'password123',
name: 'Test User'
});
const userId = createResponse.body.id;
const response = await request.get(`/api/users/${userId}`);
expect(response.status).toBe(200);
expect(response.body.id).toBe(userId);
expect(response.body.email).toBe('test@example.com');
});
it('should return 404 when user not found', async () => {
const response = await request.get('/api/users/non-existent-id');
expect(response.status).toBe(404);
expect(response.body.error).toBe('User not found');
});
});
});
六、测试质量优化
6.1 测试重构
typescript
class TestRefactoringHelper {
// 优化测试代码质量
async refactorTests(testCode: string): Promise<RefactoredTests> {
const prompt = `
请优化以下测试代码:
测试代码:
${testCode}
优化要求:
1. 消除重复代码
2. 提取公共测试逻辑
3. 优化测试名称
4. 改进断言方式
5. 添加测试注释
6. 提高测试可读性
请输出优化后的测试代码。
`;
const result = await atomCode.generate(prompt);
return this.parseRefactoredTests(result);
}
// 检测测试代码异味
async detectTestSmells(testCode: string): Promise<TestSmell[]> {
const prompt = `
请分析以下测试代码,识别测试代码异味:
测试代码:
${testCode}
需要检测的代码异味:
1. 断言滥用
2. 测试名称不清晰
3. 测试过于冗长
4. 测试间相互依赖
5. Mock 过多或过少
6. 硬编码测试数据
7. 缺乏测试隔离
请标记所有问题并提供修复建议。
`;
const result = await atomCode.analyze(prompt);
return this.parseTestSmells(result);
}
}
6.2 测试代码异味修复示例
typescript
// 修复前的测试代码
describe('Calculator', () => {
it('test add', () => {
const calc = new Calculator();
expect(calc.add(1, 2)).toBe(3);
expect(calc.add(0, 0)).toBe(0);
expect(calc.add(-1, 1)).toBe(0);
});
it('test subtract', () => {
const calc = new Calculator();
expect(calc.subtract(5, 3)).toBe(2);
expect(calc.subtract(0, 0)).toBe(0);
expect(calc.subtract(-1, -1)).toBe(0);
});
});
// 修复后的测试代码 - 由 AtomCode 生成
describe('Calculator', () => {
let calculator: Calculator;
// 提取公共设置逻辑
beforeEach(() => {
calculator = new Calculator();
});
describe('add', () => {
// 参数化测试
const addTestCases = [
{ a: 1, b: 2, expected: 3, description: 'positive numbers' },
{ a: 0, b: 0, expected: 0, description: 'zeros' },
{ a: -1, b: 1, expected: 0, description: 'negative and positive' },
{ a: 100, b: 200, expected: 300, description: 'large numbers' }
];
test.each(addTestCases)(
'should return $expected when adding $description',
({ a, b, expected }) => {
const result = calculator.add(a, b);
expect(result).toBe(expected);
}
);
});
describe('subtract', () => {
const subtractTestCases = [
{ a: 5, b: 3, expected: 2, description: 'positive numbers' },
{ a: 0, b: 0, expected: 0, description: 'zeros' },
{ a: -1, b: -1, expected: 0, description: 'negative numbers' },
{ a: 10, b: 15, expected: -5, description: 'result is negative' }
];
test.each(subtractTestCases)(
'should return $expected when subtracting $description',
({ a, b, expected }) => {
const result = calculator.subtract(a, b);
expect(result).toBe(expected);
}
);
});
});
七、测试自动化集成
7.1 CI/CD 测试集成
typescript
class TestCIIntegration {
// 生成测试流水线配置
async generateTestPipeline(): Promise<PipelineConfig> {
const prompt = `
请为项目生成 CI/CD 测试流水线配置:
项目技术栈:
- Node.js + TypeScript
- Jest 测试框架
- GitHub Actions
测试要求:
1. 代码推送时自动运行测试
2. PR 合并前运行测试
3. 生成测试覆盖率报告
4. 测试失败时阻止合并
5. 缓存依赖加速构建
请提供完整的 GitHub Actions 配置文件。
`;
const result = await atomCode.generate(prompt);
return this.parsePipelineConfig(result);
}
// 生成测试覆盖率徽章配置
async generateCoverageBadge(): Promise<BadgeConfig> {
return {
provider: 'codecov',
branch: 'main',
thresholds: {
global: 80,
patch: 70
},
failIfNotMet: true
};
}
}
7.2 GitHub Actions 配置示例
yaml
# .github/workflows/test.yml - 由 AtomCode 生成
name: Test Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run unit tests
run: npm test -- --coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: ./coverage/clover.xml
flags: unit-tests
name: codecov-umbrella
fail_ci_if_error: true
verbose: true
八、实战案例:电商订单服务测试
8.1 测试生成流程
typescript
class OrderServiceTestGenerator {
// 订单服务测试生成
async generateOrderServiceTests(): Promise<OrderTestSuite> {
const serviceCode = `
class OrderService {
constructor(
private orderRepository: OrderRepository,
private productService: ProductService,
private paymentService: PaymentService,
private notificationService: NotificationService
) {}
async createOrder(orderData: CreateOrderDto): Promise<Order> {
// 验证商品库存
const products = await Promise.all(
orderData.items.map(item => this.productService.getProduct(item.productId))
);
// 检查库存
for (const (product, item) of zip(products, orderData.items)) {
if (product.stock < item.quantity) {
throw new InsufficientStockError(product.id);
}
}
// 创建订单
const order = await this.orderRepository.create({
userId: orderData.userId,
items: orderData.items,
totalAmount: this.calculateTotal(products, orderData.items),
status: 'pending'
});
// 扣减库存
await Promise.all(
orderData.items.map(item =>
this.productService.decreaseStock(item.productId, item.quantity)
)
);
// 发起支付
await this.paymentService.createPayment(order.id, order.totalAmount);
// 发送通知
await this.notificationService.sendOrderNotification(order);
return order;
}
}
`;
const testPrompt = `
请为以下订单服务生成完整的单元测试:
服务代码:
${serviceCode}
测试场景:
1. 正常创建订单
2. 商品库存不足
3. 支付失败
4. 部分商品不存在
测试要求:
1. Mock 所有外部依赖
2. 使用 Jest 框架
3. 覆盖所有分支
4. 添加详细注释
5. 提供测试数据
请输出完整的测试代码。
`;
const result = await atomCode.generate(testPrompt);
return this.parseOrderTestSuite(result);
}
}
8.2 生成的订单服务测试
typescript
// 订单服务测试 - 由 AtomCode 生成
describe('OrderService', () => {
let orderService: OrderService;
let mockOrderRepository: jest.Mocked<OrderRepository>;
let mockProductService: jest.Mocked<ProductService>;
let mockPaymentService: jest.Mocked<PaymentService>;
let mockNotificationService: jest.Mocked<NotificationService>;
beforeEach(() => {
mockOrderRepository = {
create: jest.fn(),
findById: jest.fn()
};
mockProductService = {
getProduct: jest.fn(),
decreaseStock: jest.fn()
};
mockPaymentService = {
createPayment: jest.fn()
};
mockNotificationService = {
sendOrderNotification: jest.fn()
};
orderService = new OrderService(
mockOrderRepository,
mockProductService,
mockPaymentService,
mockNotificationService
);
});
describe('createOrder', () => {
it('should create order successfully when all conditions met', async () => {
// Arrange
const mockProducts = [
{ id: 'p1', name: 'Product 1', price: 100, stock: 10 },
{ id: 'p2', name: 'Product 2', price: 200, stock: 5 }
];
const orderData = {
userId: 'u1',
items: [
{ productId: 'p1', quantity: 2 },
{ productId: 'p2', quantity: 1 }
]
};
const mockOrder = {
id: 'o1',
userId: 'u1',
items: orderData.items,
totalAmount: 400,
status: 'pending'
};
mockProductService.getProduct.mockImplementation((id: string) =>
Promise.resolve(mockProducts.find(p => p.id === id))
);
mockOrderRepository.create.mockResolvedValue(mockOrder);
mockProductService.decreaseStock.mockResolvedValue();
mockPaymentService.createPayment.mockResolvedValue();
mockNotificationService.sendOrderNotification.mockResolvedValue();
// Act
const result = await orderService.createOrder(orderData);
// Assert
expect(mockProductService.getProduct).toHaveBeenCalledTimes(2);
expect(mockOrderRepository.create).toHaveBeenCalledWith(expect.objectContaining({
totalAmount: 400,
status: 'pending'
}));
expect(mockProductService.decreaseStock).toHaveBeenCalledTimes(2);
expect(mockPaymentService.createPayment).toHaveBeenCalledWith('o1', 400);
expect(mockNotificationService.sendOrderNotification).toHaveBeenCalledWith(mockOrder);
expect(result).toEqual(mockOrder);
});
it('should throw InsufficientStockError when stock is insufficient', async () => {
// Arrange
const mockProducts = [
{ id: 'p1', name: 'Product 1', price: 100, stock: 1 }
];
const orderData = {
userId: 'u1',
items: [{ productId: 'p1', quantity: 5 }]
};
mockProductService.getProduct.mockResolvedValue(mockProducts[0]);
// Act & Assert
await expect(orderService.createOrder(orderData))
.rejects
.toThrow(new InsufficientStockError('p1'));
});
it('should handle payment failure gracefully', async () => {
// Arrange
const mockProducts = [
{ id: 'p1', name: 'Product 1', price: 100, stock: 10 }
];
const orderData = {
userId: 'u1',
items: [{ productId: 'p1', quantity: 1 }]
};
const mockOrder = { id: 'o1', userId: 'u1', items: orderData.items, totalAmount: 100, status: 'pending' };
mockProductService.getProduct.mockResolvedValue(mockProducts[0]);
mockOrderRepository.create.mockResolvedValue(mockOrder);
mockProductService.decreaseStock.mockResolvedValue();
mockPaymentService.createPayment.mockRejectedValue(new PaymentFailedError());
// Act & Assert
await expect(orderService.createOrder(orderData))
.rejects
.toThrow(PaymentFailedError);
});
});
});
九、最佳实践与经验总结
9.1 AI 测试生成最佳实践
typescript
interface AITestingBestPractices {
practices: [
{
name: '代码准备',
description: '确保代码有良好的类型定义和注释',
benefit: '提高测试生成准确性'
},
{
name: '分阶段生成',
description: '先生成基础测试,再逐步完善',
benefit: '降低复杂度,便于调试'
},
{
name: '人工审查',
description: 'AI 生成后进行人工审查',
benefit: '确保测试质量和安全性'
},
{
name: '持续迭代',
description: '代码变更时重新生成相关测试',
benefit: '保持测试与代码同步'
},
{
name: '数据驱动',
description: '使用参数化测试覆盖更多场景',
benefit: '提高测试覆盖率'
}
];
}
9.2 测试质量度量指标
typescript
interface TestQualityMetrics {
metrics: [
{
name: '代码覆盖率',
description: '测试覆盖的代码比例',
target: '>= 80%',
tools: ['Jest Coverage', 'Istanbul']
},
{
name: '测试执行时间',
description: '测试套件运行时间',
target: '< 5分钟',
tools: ['Jest', 'Cypress']
},
{
name: '测试稳定性',
description: '测试通过率',
target: '>= 99%',
tools: ['Jest', 'GitHub Actions']
},
{
name: '测试密度',
description: '每千行代码的测试数量',
target: '>= 10 测试/千行',
tools: ['Codecov']
}
];
}
十、总结与展望
本文详细展示了如何利用 AtomCode 实现 AI 辅助的单元测试生成,从代码分析、测试用例生成到测试质量优化的全流程实践。
核心价值回顾:
- 🔍 智能分析:理解代码结构和业务逻辑
- 📝 自动生成:生成完整的测试代码和 Mock
- 🎯 全覆盖:覆盖正常流程、边界条件、异常场景
- ⚡ 提效率:将测试编写时间减少 50-70%
- 🔄 持续集成:无缝集成到 CI/CD 流水线
测试演进方向:
- AI 驱动的测试用例优先级排序
- 基于代码变更的增量测试生成
- AI 辅助的测试调试和故障定位
- 智能测试数据生成
- AI 驱动的测试覆盖率优化
给团队的建议:
- 建立测试自动化文化
- 使用 AtomCode 提高测试效率
- 设置合理的测试覆盖率目标
- 定期审查测试质量
AI 正在重新定义测试开发的方式,让开发者能够更专注于业务逻辑,而将繁琐的测试工作交给智能助手。
本文为原创内容,基于真实项目测试开发经验整理。如需转载,请注明出处。