Skip to content

22.7 外掛測試與除錯

概述

測試與除錯是外掛開發過程中的重要環節,確保外掛質量和穩定性。本章節將詳細介紹 Claude Code 外掛的測試策略、除錯技術和最佳實踐。

测试策略

1. 测试金字塔

外掛測試應遵循測試金字塔原則:

    bash


              UI 测试
            /
          集成测试
        /
      单元测试


  * **單元測試** :測試最小的功能單元(函式、方法)
  * **整合測試** :測試外掛內部元件之間的互動
  * **UI 測試** :測試外掛與使用者介面的互動

### 2\. 测试类型

#### 单元测试

單元測試關注外掛的最小功能單元:

python
    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');
        });
      });
    });

#### 集成测试

整合測試關注外掛內部元件之間的互動:

python
    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: 'john@example.com' });

        const storedUser = await databaseService.getUser(user.id);
        expect(storedUser).toBeDefined();
        expect(storedUser.name).toBe('John');
      });
    });

#### 端到端测试

端到端測試關注外掛與系統的互動:

python
    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: 'john@example.com'
        });

        expect(result.success).toBe(true);
        expect(result.data.user.id).toBeDefined();
      });
    });

## 测试框架与工具

### 1\. Jest

Jest 是一個流行的 JavaScript 測試框架:

    json


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

### 2\. Mocha

Mocha 是一個靈活的 JavaScript 測試框架:

    json


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

### 3\. Vitest

Vitest 是一個快速的 Vite-native 測試框架:

    json


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

## 调试技术

### 1\. 日志调试

使用日誌記錄外掛執行時資訊:

python
    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;
        }
      }
    }

### 2\. 断点调试

使用 VS Code 進行斷點除錯:

    json


    // .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"]
        }
      ]
    }

### 3\. 远程调试

外掛支援遠端除錯:

    typescript


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

## 测试环境搭建

### 1\. 测试数据库

使用測試資料庫進行整合測試:

javascript
    typescript


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

### 2\. 测试替身

使用測試替身模擬外部依賴:

python
    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: 'john@example.com' });

        expect(emailService.send.calledOnce).toBe(true);
        expect(emailService.send.calledWith('john@example.com', 'Welcome')).toBe(true);
      });
    });

### 3\. 测试数据

使用測試資料進行測試:

python
    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
    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

### 2\. GitLab CI

使用 GitLab CI 進行持續整合:

yaml
    yaml


    # .gitlab-ci.yml
    stages:
      - test

    unit_test:
      stage: test
      image: node:18
      script:
        - npm install
        - npm test

## 性能测试

### 1\. 基准测试

使用基準測試評估外掛效能:

python
    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();

### 2\. 负载测试

使用負載測試評估外掛在高併發下的效能:

python
    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: 'test@example.com'
      }), {
        headers: { 'Content-Type': 'application/json' }
      });
      sleep(1);
    }

## 测试覆盖率

### 1\. 覆盖率报告

使用 Jest 生成覆蓋率報告:

    json


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

### 2\. 覆盖率阈值

設定覆蓋率閾值確保測試質量:

    json


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

## 调试技巧

### 1\. 日志级别

使用不同的日誌級別除錯:

javascript
    typescript


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

### 2\. 调试工具

使用 Chrome DevTools 除錯:

    bash


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

### 3\. 错误追踪

使用 Sentry 進行錯誤追蹤:

python
    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. 測試隔離

確保測試之間相互隔離:

javascript
    typescript


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

### 3\. 测试命名

使用清晰的測試命名規範:

javascript
    typescript


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

        it('should throw error with invalid data', async () => {
          // ...
        });
      });
    });

### 4\. 测试文档

為測試編寫文件:

javascript
    typescript


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

## 常见问题

### Q: 如何测试异步代码?

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

    typescript


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

### Q: 如何测试错误情况?

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

    typescript


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

### Q: 如何测试定时器?

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

    typescript


    it('should execute after delay', async () => {
      jest.useFakeTimers();

      const callback = jest.fn();
      setTimeout(callback, 1000);

      jest.runAllTimers();
      expect(callback).toHaveBeenCalled();
    });

## 总结

測試與除錯是外掛開發過程中的重要環節。透過採用合適的測試策略、使用測試框架和工具、遵循最佳實踐,可以確保外掛的質量和穩定性。

下一章將介紹外掛效能最佳化技術,幫助開發者提高外掛效能和響應性。

基于 MIT 许可发布 | 永久导航