22.7 插件测试与调试

概述

测试与调试是插件开发过程中的重要环节,确保插件质量和稳定性。本章节将详细介绍 Claude Code 插件的测试策略、调试技术和最佳实践。

测试策略

1. 测试金字塔

插件测试应遵循测试金字塔原则:

              UI 测试
            /
          集成测试
        /
      单元测试
  • 单元测试 :测试最小的功能单元(函数、方法)
  • 集成测试 :测试插件内部组件之间的交互
  • UI 测试 :测试插件与用户界面的交互

2. 测试类型

单元测试

单元测试关注插件的最小功能单元:

    typescript
 
    // 单元测试示例
    import { CalculatorTool } from './calculator-tool';
 
    describe('CalculatorTool', () => {
      let tool: CalculatorTool;
 
      beforeEach(() => {
        tool = new CalculatorTool();
      });
 
      describe('add', () => {
        it('should add two numbers', async () => {
          const result = await tool.execute({ operation: 'add', a: 2, b: 3 });
          expect(result).toBe(5);
        });
 
        it('should handle negative numbers', async () => {
          const result = await tool.execute({ operation: 'add', a: -2, b: 3 });
          expect(result).toBe(1);
        });
      });
 
      describe('validate', () => {
        it('should validate required parameters', () => {
          const result = tool.validate({});
          expect(result.valid).toBe(false);
          expect(result.error).toBe('Operation is required');
        });
      });
    });

集成测试关注插件内部组件之间的交互:

    typescript
 
    // 集成测试示例
    import { UserPlugin } from './user-plugin';
    import { DatabaseService } from './database-service';
 
    describe('UserPlugin', () => {
      let plugin: UserPlugin;
      let databaseService: DatabaseService;
 
      beforeEach(() => {
        databaseService = new DatabaseService();
        plugin = new UserPlugin({ databaseService });
      });
 
      it('should create user and store in database', async () => {
        const user = await plugin.createUser({ name: 'John', email: '[email protected]' });
 
        const storedUser = await databaseService.getUser(user.id);
        expect(storedUser).toBeDefined();
        expect(storedUser.name).toBe('John');
      });
    });

端到端测试关注插件与系统的交互:

    typescript
 
    // 端到端测试示例
    import { PluginManager } from '@claude-code/plugin-sdk';
 
    describe('UserPlugin E2E', () => {
      let pluginManager: PluginManager;
 
      beforeAll(async () => {
        pluginManager = new PluginManager();
        await pluginManager.loadPlugin('user-plugin');
      });
 
      afterAll(async () => {
        await pluginManager.unloadPlugin('user-plugin');
      });
 
      it('should create user through plugin API', async () => {
        const result = await pluginManager.executeCommand('user:create', {
          name: 'John',
          email: '[email protected]'
        });
 
        expect(result.success).toBe(true);
        expect(result.data.user.id).toBeDefined();
      });
    });

测试框架与工具

1. Jest

Jest 是一个流行的 JavaScript 测试框架:

// package.json
{
  "devDependencies": {
    "jest": "^29.0.0",
    "@types/jest": "^29.0.0"
  },
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  }
}

Mocha 是一个灵活的 JavaScript 测试框架:

// package.json
{
  "devDependencies": {
    "mocha": "^10.0.0",
    "chai": "^4.0.0",
    "sinon": "^15.0.0"
  },
  "scripts": {
    "test": "mocha",
    "test:watch": "mocha --watch"
  }
}

Vitest 是一个快速的 Vite-native 测试框架:

// package.json
{
  "devDependencies": {
    "vitest": "^0.30.0"
  },
  "scripts": {
    "test": "vitest",
    "test:ui": "vitest --ui"
  }
}

调试技术

1. 日志调试

使用日志记录插件运行时信息:

    typescript
 
    // 日志调试示例
    class UserPlugin {
      async createUser(userData) {
        this.logger.debug('Creating user', { userData });
 
        try {
          const user = await this.database.create(userData);
          this.logger.info('User created', { userId: user.id });
          return user;
        } catch (error) {
          this.logger.error('Failed to create user', { error: error.message });
          throw error;
        }
      }
    }

使用 VS Code 进行断点调试:

// .vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug Plugin",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/src/plugin.ts",
      "args": ["--debug"],
      "outFiles": ["${workspaceFolder}/dist/**/*.js"]
    }
  ]
}

插件支持远程调试:

// 启用远程调试
if (process.env.NODE_ENV === "development") {
  require("inspector").open(9229, "0.0.0.0", true);
}

测试环境搭建

1. 测试数据库

使用测试数据库进行集成测试:

typescript;
 
// 测试数据库配置
const testConfig = {
  database: {
    type: "sqlite",
    database: ":memory:",
    synchronize: true,
    logging: false,
  },
};

使用测试替身模拟外部依赖:

    typescript
 
    // 使用 Sinon 模拟依赖
    import sinon from 'sinon';
 
    describe('UserPlugin', () => {
      it('should send welcome email', async () => {
        const emailService = { send: sinon.stub().resolves(true) };
        const plugin = new UserPlugin({ emailService });
 
        await plugin.createUser({ name: 'John', email: '[email protected]' });
 
        expect(emailService.send.calledOnce).toBe(true);
        expect(emailService.send.calledWith('[email protected]', 'Welcome')).toBe(true);
      });
    });

使用测试数据进行测试:

    typescript
 
    // 测试数据生成
    function generateTestUser() {
      return {
        name: `Test User ${Math.random().toString(36).substring(2, 10)}`,
        email: `test-${Math.random().toString(36).substring(2, 10)}@example.com`,
        password: 'password123'
      };
    }
 
    // 批量生成测试数据
    function generateTestUsers(count: number) {
      return Array.from({ length: count }, () => generateTestUser());
    }

持续集成

1. GitHub Actions

使用 GitHub Actions 进行持续集成:

    yaml
 
    # .github/workflows/test.yml
    name: Test
 
    on: [push, pull_request]
 
    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
          - uses: actions/setup-node@v3
            with:
              node-version: 18
          - run: npm install
          - run: npm test
          - run: npm run lint

使用 GitLab CI 进行持续集成:

    yaml
 
    # .gitlab-ci.yml
    stages:
      - test
 
    unit_test:
      stage: test
      image: node:18
      script:
        - npm install
        - npm test

性能测试

1. 基准测试

使用基准测试评估插件性能:

    typescript
 
    // 基准测试示例
    import { suite } from 'benchmark';
    import { CalculatorTool } from './calculator-tool';
 
    const tool = new CalculatorTool();
 
    const bench = new suite('CalculatorTool');
 
    bench
      .add('add', async (deferred) => {
        await tool.execute({ operation: 'add', a: 2, b: 3 });
        deferred.resolve();
      }, { defer: true })
      .add('multiply', async (deferred) => {
        await tool.execute({ operation: 'multiply', a: 2, b: 3 });
        deferred.resolve();
      }, { defer: true })
      .on('cycle', (event) => {
        console.log(String(event.target));
      })
      .run();

使用负载测试评估插件在高并发下的性能:

    typescript
 
    // 负载测试示例
    import http from 'k6/http';
    import { sleep } from 'k6';
 
    export const options = {
      vus: 100,
      duration: '30s'
    };
 
    export default function () {
      http.post('http://localhost:3000/api/users', JSON.stringify({
        name: 'Test User',
        email: '[email protected]'
      }), {
        headers: { 'Content-Type': 'application/json' }
      });
      sleep(1);
    }

测试覆盖率

1. 覆盖率报告

使用 Jest 生成覆盖率报告:

// package.json
{
  "scripts": {
    "test:coverage": "jest --coverage"
  }
}

设置覆盖率阈值确保测试质量:

    // jest.config.js
    module.exports = {
      coverageThreshold: {
        global: {
          branches: 80,
          functions: 80,
          lines: 80,
          statements: 80
        }
      }
    };

调试技巧

1. 日志级别

使用不同的日志级别调试:

typescript;
 
// 日志级别配置
const logger = createLogger({
  level: process.env.NODE_ENV === "development" ? "debug" : "info",
});

使用 Chrome DevTools 调试:

    # 启动调试模式
    node --inspect-brk plugin.js

使用 Sentry 进行错误追踪:

    typescript
 
    // Sentry 配置
    import * as Sentry from '@sentry/node';
 
    Sentry.init({
      dsn: 'your-sentry-dsn',
      environment: process.env.NODE_ENV
    });

最佳实践

1. 测试驱动开发

采用测试驱动开发(TDD):

  1. 编写失败的测试
  2. 编写足够的代码使测试通过
  3. 重构代码
  4. 重复

2. 测试隔离

确保测试之间相互隔离:

typescript;
 
// 测试隔离示例
beforeEach(() => {
  // 重置状态
  database.clear();
  cache.clear();
});

使用清晰的测试命名规范:

typescript;
 
// 测试命名示例
describe("UserPlugin", () => {
  describe("createUser", () => {
    it("should create user with valid data", async () => {
      // ...
    });
 
    it("should throw error with invalid data", async () => {
      // ...
    });
  });
});

为测试编写文档:

typescript;
 
// 测试文档示例
/**
 * 测试用户创建功能
 * 1. 验证必填字段
 * 2. 验证数据存储
 * 3. 验证错误处理
 */
describe("UserPlugin.createUser", () => {
  // ...
});

常见问题

Q: 如何测试异步代码?

A: 使用 async/await 测试异步代码:

it("should handle async operation", async () => {
  const result = await asyncFunction();
  expect(result).toBe(true);
});

Q: 如何测试错误情况?

A: 使用 expect.toThrow 测试错误情况:

it("should throw error with invalid data", async () => {
  await expect(plugin.createUser({})).rejects.toThrow("Invalid data");
});

Q: 如何测试定时器?

A: 使用 Jest 的定时器模拟:

it("should execute after delay", async () => {
  jest.useFakeTimers();
 
  const callback = jest.fn();
  setTimeout(callback, 1000);
 
  jest.runAllTimers();
  expect(callback).toHaveBeenCalled();
});

总结

测试与调试是插件开发过程中的重要环节。通过采用合适的测试策略、使用测试框架和工具、遵循最佳实践,可以确保插件的质量和稳定性。

下一章将介绍插件性能优化技术,帮助开发者提高插件性能和响应性。