关键测试解析(上):Plan Parser、State Machine、Agent Delegator

📑 目录

这是「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.jsonUTF-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: abort

2.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 的生命周期测试。敬请期待。