smithery/protagonistss

mock-generation

生成测试所需的 Mock 数据与 Stub 函数。 当用户说"生成mock"、"创建mock"、"模拟数据"、"mock函数"、"stub函数"、"测试数据"、"模拟API"、"mock数据库"时使用此技能。 支持多框架 Mock:Jest (jest.fn/mock)、Vitest (vi.fn/vi.mock)、Python (unittest.mock/pytest-mock)。 生成 Mock 模块、Stub 函数、测试数据工厂、API 响应 Mock、数据库 Mock、时间 Mock。输出完整的 Mock ?

Installation

$ npx skills add smithery/protagonistss --skill mock-generation

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/protagonistss.

npx skills add smithery/protagonistss

Browse all from smithery/protagonistss

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 10,232 B
  • docs SUMMARY.md 74 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Mock生成技能

这个技能专门负责生成测试所需的Mock数据和Stub函数,帮助隔离测试环境并提高测试效率。

技能能力

1. 依赖分析

  • 自动识别需要Mock的外部依赖
  • 分析函数签名和返回值类型
  • 检测数据库操作、API调用等外部交互
  • 识别时间和随机等不可控因素

2. Mock数据生成

  • 生成符合类型定义的Mock对象
  • 创建真实的测试数据集
  • 支持复杂嵌套对象的生成
  • 生成边界值和异常数据

3. Stub函数创建

  • 创建可控的函数替代品
  • 支持多种返回值模式
  • 记录调用历史和参数
  • 模拟异步操作

使用方式

基础Mock生成

// 为模块生成Mock
await generateMock('src/api/userService', {
  framework: 'vitest',
  includeReturnValues: true
});

// 为特定函数生成Mock
await generateFunctionMock('fetchUserData', {
  returnType: 'User',
  async: true,
  errorScenarios: true
});

高级选项

await generateMock(target, {
  framework: 'vitest',
  mockType: 'auto', // 'auto' | 'partial' | 'full'
  includeSpies: true,
  generateTestData: true,
  customReturnValues: {
    'getUser': () => ({ id: 1, name: 'Test User' }),
    'createUser': () => Promise.resolve({ success: true })
  }
});

Mock模板

Jest模板

// Mock整个模块
jest.mock('{{modulePath}}', () => ({
  {{#each exports}}
  {{name}}: jest.fn(),
  {{/each}}
}));

// Mock实现
{{#each exports}}
{{name}}.mockImplementation(({{
  #if isAsync}}
  {{#if hasParams}}
  async ({ {{join params ", "}} }) => {
    // Mock implementation
    return {{defaultValue}};
  }
  {{else}}
  async () => {
    return {{defaultValue}};
  }
  {{/if}}
  {{else}}
  {{#if hasParams}}
  ({ {{join params ", "}} }) => {
    // Mock implementation
    return {{defaultValue}};
  }
  {{else}}
  () => {
    return {{defaultValue}};
  }
  {{/if}}
  {{/if}}
}));
{{/each}}

// 在测试中使用
beforeEach(() => {
  {{#each exports}}
  {{name}}.mockClear();
  {{/each}}
});

Vitest模板

import { vi } from 'vitest';

// Mock整个模块
vi.mock('{{modulePath}}', () => ({
  {{#each exports}}
  {{name}}: vi.fn(),
  {{/each}}
}));

// Mock实现
{{#each exports}}
export const {{name}} = vi.fn();
{{#if isAsync}}
{{name}}.mockResolvedValue({{defaultValue}});
{{else}}
{{name}}.mockReturnValue({{defaultValue}});
{{/if}}
{{/each}}

Python Mock模板

from unittest.mock import Mock, patch
import pytest

{{#each functions}}
# Mock decorator
@patch('{{modulePath}}.{{name}}')
def test_{{testName}}(mock_{{name}}):
    # Setup mock return value
    mock_{{name}}.return_value = {{defaultValue}}

    # Test implementation
    result = function_under_test()

    # Assertions
    assert result is not None
    {{#if verifyCalled}}
    mock_{{name}}.assert_called_once()
    {{/if}}
{{/each}}

数据生成器

基础类型生成器

class DataGenerator {
  static generateString(options?: {
    length?: number;
    pattern?: string;
    enum?: string[];
  }): string {
    if (options?.enum) {
      return options.enum[0];
    }

    if (options?.pattern) {
      return this.matchPattern(options.pattern);
    }

    const length = options?.length || 10;
    return this.randomString(length);
  }

  static generateNumber(options?: {
    min?: number;
    max?: number;
    integer?: boolean;
    enum?: number[];
  }): number {
    if (options?.enum) {
      return options.enum[0];
    }

    const min = options?.min || 0;
    const max = options?.max || 100;

    if (options?.integer) {
      return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    return Math.random() * (max - min) + min;
  }

  static generateArray<T>(itemGenerator: () => T, options?: {
    length?: number;
    minLength?: number;
    maxLength?: number;
  }): T[] {
    const length = options?.length ||
      Math.floor(Math.random() * (options?.maxLength || 5)) + (options?.minLength || 0);

    return Array.from({ length }, itemGenerator);
  }

  static generateObject(schema: ObjectSchema): any {
    const obj: any = {};

    for (const [key, value] of Object.entries(schema)) {
      if (typeof value === 'function') {
        obj[key] = value();
      } else if (Array.isArray(value)) {
        obj[key] = this.generateArray(() => value[0]);
      } else if (typeof value === 'object') {
        obj[key] = this.generateObject(value);
      } else {
        obj[key] = value;
      }
    }

    return obj;
  }
}

复杂对象生成

// 用户对象生成器
const UserGenerator = {
  generate: (overrides?: Partial<User>): User => ({
    id: DataGenerator.generateNumber({ integer: true, min: 1 }),
    name: DataGenerator.generateString({ length: 10 }),
    email: DataGenerator.generateEmail(),
    age: DataGenerator.generateNumber({ min: 18, max: 65, integer: true }),
    isActive: true,
    createdAt: new Date().toISOString(),
    ...overrides
  }),

  generateList: (count: number = 3): User[] =>
    DataGenerator.generateArray(() => UserGenerator.generate(), { length: count }),

  generateWithInvalidData: (): User => ({
    id: -1,
    name: '',
    email: 'invalid-email',
    age: -1,
    isActive: false,
    createdAt: 'invalid-date'
  })
};

API Mock生成

REST API Mock

// API响应生成器
class APIResponseGenerator {
  static generateSuccessResponse<T>(data: T): APIResponse<T> {
    return {
      success: true,
      data,
      message: 'Success',
      timestamp: new Date().toISOString()
    };
  }

  static generateErrorResponse(errorCode: string, message: string): APIResponse<null> {
    return {
      success: false,
      data: null,
      error: {
        code: errorCode,
        message,
        details: {}
      },
      timestamp: new Date().toISOString()
    };
  }

  static generatePaginatedResponse<T>(
    items: T[],
    page: number = 1,
    limit: number = 10
  ): PaginatedResponse<T> {
    return {
      success: true,
      data: items,
      pagination: {
        page,
        limit,
        total: items.length,
        totalPages: Math.ceil(items.length / limit)
      }
    };
  }
}

// Fetch Mock
const mockFetch = jest.fn();
mockFetch.mockImplementation(async (url: string, options?: RequestInit) => {
  if (url.includes('/users')) {
    return {
      ok: true,
      status: 200,
      json: async () => APIResponseGenerator.generateSuccessResponse(
        UserGenerator.generateList()
      )
    };
  }

  if (url.includes('/error')) {
    return {
      ok: false,
      status: 500,
      json: async () => APIResponseGenerator.generateErrorResponse(
        'INTERNAL_ERROR',
        'Something went wrong'
      )
    };
  }

  return {
    ok: false,
    status: 404,
    json: async () => ({})
  };
});

数据库Mock

数据库操作Mock

// 数据库连接Mock
const mockDb = {
  users: {
    findById: jest.fn(),
    create: jest.fn(),
    update: jest.fn(),
    delete: jest.fn(),
    findMany: jest.fn()
  },
  transactions: {
    begin: jest.fn(),
    commit: jest.fn(),
    rollback: jest.fn()
  }
};

// 设置Mock返回值
mockDb.users.findById.mockImplementation(async (id: number) => {
  if (id === 999) {
    return null;
  }
  return UserGenerator.generate({ id });
});

mockDb.users.create.mockImplementation(async (userData: Partial<User>) => {
  return UserGenerator.generate(userData);
});

时间Mock

时间相关测试

// Jest时间Mock
beforeEach(() => {
  jest.useFakeTimers();
});

afterEach(() => {
  jest.useRealTimers();
});

// 测试中的时间控制
it('should execute callback after delay', () => {
  const callback = jest.fn();

  setTimeout(callback, 1000);

  // 快进时间
  jest.advanceTimersByTime(1000);

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

// Vitest时间Mock
import { vi } from 'vitest';

beforeEach(() => {
  vi.useFakeTimers();
});

afterEach(() => {
  vi.useRealTimers();
});

特殊场景Mock

错误场景

// 错误Mock生成器
class ErrorMockGenerator {
  static generateNetworkError(): Error {
    const error = new Error('Network Error');
    error.name = 'NetworkError';
    error.code = 'NETWORK_ERROR';
    return error;
  }

  static generateTimeoutError(): Error {
    const error = new Error('Request timeout');
    error.name = 'TimeoutError';
    error.code = 'TIMEOUT';
    return error;
  }

  static generateValidationError(field: string): Error {
    const error = new Error(`Validation failed for field: ${field}`);
    error.name = 'ValidationError';
    error.field = field;
    return error;
  }
}

// 使用错误Mock
mockApi.getUser.mockRejectedValue(ErrorMockGenerator.generateNetworkError());

异步操作

// 异步操作Mock
const asyncMock = jest.fn();
asyncMock
  .mockResolvedValueOnce('first call result')
  .mockRejectedValueOnce(new Error('second call error'))
  .mockResolvedValueOnce('third call result');

// Promise链测试
it('should handle promise chain', async () => {
  const result = await promiseChain();

  expect(result).toBe('final result');
  expect(asyncMock).toHaveBeenCalledTimes(3);
});

最佳实践

1. Mock范围控制

  • 只Mock外部依赖
  • 避免过度Mock
  • 保持Mock简单

2. Mock数据管理

  • 使用工厂模式生成测试数据
  • 创建可重用的数据集
  • 保持数据一致性

3. Mock验证

  • 验证Mock的调用
  • 检查调用参数
  • 确保Mock被正确使用

4. 清理和重置

  • 在每个测试后重置Mock
  • 避免测试间的干扰
  • 使用beforeEach/afterEach