这是「GSD 全景代码解析」专题的第 49 篇。
一、Plan Parser 测试解析
plan-parser.test.js 是测试金字塔的基石之一,它验证 plan.json 从原始文本到运行时数据结构的转换正确性。
1.1 核心测试场景
describe('PlanParser', () => {
describe('parse()', () => {
test('应正确解析标准 plan.json', async () => {
const plan = await parser.parse('standard-plan.json');
expect(plan.title).toBe('示例项目');
expect(plan.tasks).toHaveLength(5);
expect(plan.tasks[0].dependencies).toEqual([]);
});
test('应处理嵌套任务结构', async () => {
const plan = await parser.parse('nested-plan.json');
expect(plan.tasks[0].subTasks).toBeDefined();
expect(plan.tasks[0].subTasks[0].id).toBe('1.1');
});
test('应验证必填字段', async () => {
await expect(parser.parse('missing-title.json'))
.rejects.toThrow(PlanValidationError);
});
test('应检测循环依赖', async () => {
await expect(parser.parse('circular-deps.json'))
.rejects.toThrow('Circular dependency detected');
});
});
});1.2 边界条件覆盖
| 边界条件 | 测试用例 | 预期行为 |
|---|---|---|
| 空任务列表 | empty-tasks.json | 返回空数组,不报错 |
| 最大任务数 | max-tasks.json (1000+) | 正常解析,性能可接受 |
| 特殊字符 | special-chars.json | UTF-8 正确编码 |
| 超大文件 | 10mb-plan.json | 流式解析,内存安全 |
| 缺失 Agent 引用 | invalid-agent.json | 抛出 AgentNotFoundError |
1.3 Mock 设计
// Mock 文件系统,避免 I/O 开销
const mockPlans = {
'standard-plan.json': JSON.stringify({
title: '示例项目',
tasks: [
{ id: '1', name: '初始化', agent: 'setup', dependencies: [] },
{ id: '2', name: '开发', agent: 'coder', dependencies: ['1'] }
]
})
};
jest.mock('fs/promises', () => ({
readFile: jest.fn((path) => {
const key = path.split('/').pop();
if (mockPlans[key]) return Promise.resolve(mockPlans[key]);
throw new Error('File not found');
})
}));二、State Machine 测试解析
state-machine.test.js 验证 GSD 核心状态转换逻辑的正确性,这是整个执行引擎的可靠性基础。
2.1 状态转换矩阵
stateDiagram-v2
[*] --> IDLE
IDLE --> PLANNING: startPlanning
PLANNING --> PLANNED: planningComplete
PLANNED --> EXECUTING: startExecution
EXECUTING --> PAUSED: pause
PAUSED --> EXECUTING: resume
EXECUTING --> COMPLETED: allTasksDone
EXECUTING --> FAILED: taskFailed
FAILED --> RETRYING: retry
RETRYING --> EXECUTING: retryComplete
FAILED --> ABORTED: abort2.2 核心测试用例
describe('StateMachine', () => {
test('应允许有效的状态转换', () => {
const sm = new StateMachine();
sm.transition('PLANNING');
expect(sm.state).toBe('PLANNING');
sm.transition('PLANNED');
expect(sm.state).toBe('PLANNED');
});
test('应拒绝无效的状态转换', () => {
const sm = new StateMachine('EXECUTING');
expect(() => sm.transition('PLANNING'))
.toThrow(InvalidTransitionError);
});
test('应支持状态历史追踪', () => {
const sm = new StateMachine();
sm.transition('PLANNING');
sm.transition('PLANNED');
sm.transition('EXECUTING');
expect(sm.history).toEqual(['IDLE', 'PLANNING', 'PLANNED', 'EXECUTING']);
});
test('转换时应触发对应钩子', () => {
const onEnterPlanning = jest.fn();
const sm = new StateMachine();
sm.onEnter('PLANNING', onEnterPlanning);
sm.transition('PLANNING');
expect(onEnterPlanning).toHaveBeenCalled();
});
});2.3 并发安全测试
test('应处理并发转换请求', async () => {
const sm = new StateMachine();
const promises = [
sm.transitionAsync('PLANNING'),
sm.transitionAsync('PLANNING'),
sm.transitionAsync('PLANNING')
];
const results = await Promise.allSettled(promises);
// 只有一个应成功,其余应被拒绝
const successCount = results.filter(r => r.status === 'fulfilled').length;
expect(successCount).toBe(1);
});三、Agent Delegator 测试解析
agent-delegator.test.js 验证 Agent 选择与调用逻辑,是 GSD 多 Agent 协作系统的核心保障。
3.1 Agent 路由测试
describe('AgentDelegator', () => {
test('应根据任务类型选择正确 Agent', async () => {
const delegator = new AgentDelegator();
const task = { type: 'CODE_REVIEW', language: 'typescript' };
const agent = await delegator.select(task);
expect(agent.name).toBe('CodeReviewer');
});
test('应支持显式 Agent 指定', async () => {
const task = { type: 'GENERIC', agent: 'CustomAgent' };
const agent = await delegator.select(task);
expect(agent.name).toBe('CustomAgent');
});
test('未知任务类型应回退到通用 Agent', async () => {
const task = { type: 'UNKNOWN_TYPE' };
const agent = await delegator.select(task);
expect(agent.name).toBe('Generalist');
});
});3.2 负载均衡测试
test('应在多个相同能力 Agent 间轮询', async () => {
const delegator = new AgentDelegator([
{ name: 'CoderA', capabilities: ['typescript'] },
{ name: 'CoderB', capabilities: ['typescript'] }
]);
const task = { type: 'CODE', language: 'typescript' };
const agent1 = await delegator.select(task);
const agent2 = await delegator.select(task);
expect(agent1.name).not.toBe(agent2.name);
});3.3 错误处理测试
test('Agent 调用失败应触发重试', async () => {
const mockAgent = {
name: 'FlakyAgent',
invoke: jest.fn()
.mockRejectedValueOnce(new Error('Timeout'))
.mockResolvedValueOnce({ result: 'success' })
};
const delegator = new AgentDelegator([mockAgent]);
const result = await delegator.invokeWithRetry(mockAgent, 'task');
expect(mockAgent.invoke).toHaveBeenCalledTimes(2);
expect(result).toEqual({ result: 'success' });
});
test('重试耗尽应抛出 AgentUnavailableError', async () => {
const mockAgent = {
name: 'BrokenAgent',
invoke: jest.fn().mockRejectedValue(new Error('Always fails'))
};
const delegator = new AgentDelegator([mockAgent], { maxRetries: 2 });
await expect(delegator.invokeWithRetry(mockAgent, 'task'))
.rejects.toThrow(AgentUnavailableError);
});四、Mock LLM 的确定性响应
const deterministicLLM = {
invoke: jest.fn(async (prompt) => {
// 基于 prompt 内容返回固定响应
const hash = crypto.createHash('md5').update(prompt).digest('hex');
return mockResponseMap[hash] || { content: '默认响应' };
})
};五、测试模式总结
| 模式 | 应用场景 | 示例 |
|---|---|---|
| 参数化测试 | 多组相似输入 | test.each(cases) |
| 快照测试 | 复杂输出验证 | toMatchSnapshot() |
| 假时间 | 时间相关逻辑 | jest.useFakeTimers() |
| 临时目录 | 文件系统测试 | os.tmpdir() |
| 并行隔离 | 无状态测试 | Promise.all() |
下一篇预告: 第 50 篇《关键测试解析(下):Context Engine、Phase Runner、Hook System》
我们将继续深入解读 Context Engine 的截断测试、Phase Runner 的集成测试,以及 Hook System 的生命周期测试。敬请期待。