技能 编程开发 Jest 测试模式与工具

Jest 测试模式与工具

v20260927
code-showcase-testing-patterns
此技能提供 Jest 测试模式、工厂函数、模拟策略和 TDD 工作流。帮助开发者编写可维护的单元测试,创建测试工厂,并遵循红绿重构循环,适用于 React Native 应用开发。
获取技能
409 次下载
概览

Testing Patterns and Utilities

When to Use

Use this skill when you need jest testing patterns, factory functions, mocking strategies, and TDD workflow. Use when writing unit tests, creating test factories, or following TDD red-green-refactor cycle.

Testing Philosophy

Test-Driven Development (TDD):

  • Write failing test FIRST
  • Implement minimal code to pass
  • Refactor after green
  • Never write production code without a failing test

Behavior-Driven Testing:

  • Test behavior, not implementation
  • Focus on public APIs and business requirements
  • Avoid testing implementation details
  • Use descriptive test names that describe behavior

Factory Pattern:

  • Create getMockX(overrides?: Partial<X>) functions
  • Provide sensible defaults
  • Allow overriding specific properties
  • Keep tests DRY and maintainable

Test Utilities

Custom Render Function

Create a custom render that wraps components with required providers:

// src/utils/testUtils.tsx
import { render } from '@testing-library/react-native';
import { ThemeProvider } from './theme';

export const renderWithTheme = (ui: React.ReactElement) => {
  return render(
    <ThemeProvider>{ui}</ThemeProvider>
  );
};

Usage:

import { renderWithTheme } from 'utils/testUtils';
import { screen } from '@testing-library/react-native';

it('should render component', () => {
  renderWithTheme(<MyComponent />);
  expect(screen.getByText('Hello')).toBeTruthy();
});

Factory Pattern

Component Props Factory

import { ComponentProps } from 'react';

const getMockMyComponentProps = (
  overrides?: Partial<ComponentProps<typeof MyComponent>>
) => {
  return {
    title: 'Default Title',
    count: 0,
    onPress: jest.fn(),
    isLoading: false,
    ...overrides,
  };
};

// Usage in tests
it('should render with custom title', () => {
  const props = getMockMyComponentProps({ title: 'Custom Title' });
  renderWithTheme(<MyComponent {...props} />);
  expect(screen.getByText('Custom Title')).toBeTruthy();
});

Data Factory

interface User {
  id: string;
  name: string;
  email: string;
  role: 'admin' | 'user';
}

const getMockUser = (overrides?: Partial<User>): User => {
  return {
    id: '123',
    name: 'John Doe',
    email: 'john@example.com',
    role: 'user',
    ...overrides,
  };
};

// Usage
it('should display admin badge for admin users', () => {
  const user = getMockUser({ role: 'admin' });
  renderWithTheme(<UserCard user={user} />);
  expect(screen.getByText('Admin')).toBeTruthy();
});

Mocking Patterns

Mocking Modules

// Mock entire module
jest.mock('utils/analytics');

// Mock with factory function
jest.mock('utils/analytics', () => ({
  Analytics: {
    logEvent: jest.fn(),
  },
}));

// Access mock in test
const mockLogEvent = jest.requireMock('utils/analytics').Analytics.logEvent;

Mocking GraphQL Hooks

jest.mock('./GetItems.generated', () => ({
  useGetItemsQuery: jest.fn(),
}));

const mockUseGetItemsQuery = jest.requireMock(
  './GetItems.generated'
).useGetItemsQuery as jest.Mock;

// In test
mockUseGetItemsQuery.mockReturnValue({
  data: { items: [] },
  loading: false,
  error: undefined,
});

Test Structure

describe('ComponentName', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('Rendering', () => {
    it('should render component with default props', () => {});
    it('should render loading state when loading', () => {});
  });

  describe('User interactions', () => {
    it('should call onPress when button is clicked', async () => {});
  });

  describe('Edge cases', () => {
    it('should handle empty data gracefully', () => {});
  });
});

Query Patterns

// Element must exist
expect(screen.getByText('Hello')).toBeTruthy();

// Element should not exist
expect(screen.queryByText('Goodbye')).toBeNull();

// Element appears asynchronously
await waitFor(() => {
  expect(screen.findByText('Loaded')).toBeTruthy();
});

User Interaction Patterns

import { fireEvent, screen } from '@testing-library/react-native';

it('should submit form on button click', async () => {
  const onSubmit = jest.fn();
  renderWithTheme(<LoginForm onSubmit={onSubmit} />);

  fireEvent.changeText(screen.getByLabelText('Email'), 'user@example.com');
  fireEvent.changeText(screen.getByLabelText('Password'), 'password123');
  fireEvent.press(screen.getByTestId('login-button'));

  await waitFor(() => {
    expect(onSubmit).toHaveBeenCalled();
  });
});

Anti-Patterns to Avoid

Testing Mock Behavior Instead of Real Behavior

// Bad - testing the mock
expect(mockFetchData).toHaveBeenCalled();

// Good - testing actual behavior
expect(screen.getByText('John Doe')).toBeTruthy();

Not Using Factories

// Bad - duplicated, inconsistent test data
it('test 1', () => {
  const user = { id: '1', name: 'John', email: 'john@test.com', role: 'user' };
});
it('test 2', () => {
  const user = { id: '2', name: 'Jane', email: 'jane@test.com' }; // Missing role!
});

// Good - reusable factory
const user = getMockUser({ name: 'Custom Name' });

Best Practices

  1. Always use factory functions for props and data
  2. Test behavior, not implementation
  3. Use descriptive test names
  4. Organize with describe blocks
  5. Clear mocks between tests
  6. Keep tests focused - one behavior per test

Running Tests

# Run all tests
npm test

# Run with coverage
npm run test:coverage

# Run specific file
npm test ComponentName.test.tsx

Integration with Other Skills

  • react-ui-patterns: Test all UI states (loading, error, empty, success)
  • systematic-debugging: Write test that reproduces bug before fixing

Limitations

  • Use this skill only when the task clearly matches its upstream source and local project context.
  • Verify commands, generated code, dependencies, credentials, and external service behavior before applying changes.
  • Do not treat examples as a substitute for environment-specific tests, security review, or user approval for destructive or costly actions.
信息
Category 编程开发
Name code-showcase-testing-patterns
版本 v20260927
大小 6.61KB
更新时间 2026-09-28
语言