testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Testing Best Practices

测试最佳实践

Comprehensive testing strategies for modern JavaScript.
面向现代JavaScript的全面测试策略。

Instructions

说明

1. Test Structure (AAA Pattern)

1. 测试结构(AAA模式)

typescript
describe('UserService', () => {
  it('should create a new user', async () => {
    // Arrange
    const userData = { name: 'John', email: 'john@example.com' };
    
    // Act
    const user = await userService.create(userData);
    
    // Assert
    expect(user.id).toBeDefined();
    expect(user.name).toBe('John');
  });
});
typescript
describe('UserService', () => {
  it('should create a new user', async () => {
    // Arrange
    const userData = { name: 'John', email: 'john@example.com' };
    
    // Act
    const user = await userService.create(userData);
    
    // Assert
    expect(user.id).toBeDefined();
    expect(user.name).toBe('John');
  });
});

2. Component Testing (React Testing Library)

2. 组件测试(React Testing Library)

tsx
import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

describe('LoginForm', () => {
  it('should submit form with credentials', async () => {
    const onSubmit = vi.fn();
    render(<LoginForm onSubmit={onSubmit} />);
    
    await userEvent.type(screen.getByLabelText('Email'), 'test@example.com');
    await userEvent.type(screen.getByLabelText('Password'), 'password123');
    await userEvent.click(screen.getByRole('button', { name: /login/i }));
    
    expect(onSubmit).toHaveBeenCalledWith({
      email: 'test@example.com',
      password: 'password123'
    });
  });
});
tsx
import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

describe('LoginForm', () => {
  it('should submit form with credentials', async () => {
    const onSubmit = vi.fn();
    render(<LoginForm onSubmit={onSubmit} />);
    
    await userEvent.type(screen.getByLabelText('Email'), 'test@example.com');
    await userEvent.type(screen.getByLabelText('Password'), 'password123');
    await userEvent.click(screen.getByRole('button', { name: /login/i }));
    
    expect(onSubmit).toHaveBeenCalledWith({
      email: 'test@example.com',
      password: 'password123'
    });
  });
});

3. Mocking

3. Mocking

typescript
// Mock module
vi.mock('./api', () => ({
  fetchUser: vi.fn().mockResolvedValue({ id: 1, name: 'John' })
}));

// Mock function
const mockFn = vi.fn();
mockFn.mockReturnValue('result');
mockFn.mockResolvedValue({ data: [] });

// Spy on method
const spy = vi.spyOn(console, 'log');
typescript
// Mock module
vi.mock('./api', () => ({
  fetchUser: vi.fn().mockResolvedValue({ id: 1, name: 'John' })
}));

// Mock function
const mockFn = vi.fn();
mockFn.mockReturnValue('result');
mockFn.mockResolvedValue({ data: [] });

// Spy on method
const spy = vi.spyOn(console, 'log');

4. Async Testing

4. 异步测试

typescript
it('should fetch user data', async () => {
  const user = await fetchUser(1);
  
  expect(user).toEqual({
    id: 1,
    name: 'John'
  });
});

it('should handle errors', async () => {
  await expect(fetchUser(-1)).rejects.toThrow('User not found');
});
typescript
it('should fetch user data', async () => {
  const user = await fetchUser(1);
  
  expect(user).toEqual({
    id: 1,
    name: 'John'
  });
});

it('should handle errors', async () => {
  await expect(fetchUser(-1)).rejects.toThrow('User not found');
});

5. Test Coverage

5. 测试覆盖率

json
// vitest.config.ts
{
  "test": {
    "coverage": {
      "provider": "v8",
      "reporter": ["text", "html"],
      "exclude": ["node_modules/", "test/"]
    }
  }
}
json
// vitest.config.ts
{
  "test": {
    "coverage": {
      "provider": "v8",
      "reporter": ["text", "html"],
      "exclude": ["node_modules/", "test/"]
    }
  }
}

6. Testing Hooks

6. Hooks测试

typescript
import { renderHook, act } from '@testing-library/react';

describe('useCounter', () => {
  it('should increment counter', () => {
    const { result } = renderHook(() => useCounter());
    
    act(() => {
      result.current.increment();
    });
    
    expect(result.current.count).toBe(1);
  });
});
typescript
import { renderHook, act } from '@testing-library/react';

describe('useCounter', () => {
  it('should increment counter', () => {
    const { result } = renderHook(() => useCounter());
    
    act(() => {
      result.current.increment();
    });
    
    expect(result.current.count).toBe(1);
  });
});

7. Test Naming Conventions

7. 测试命名规范

typescript
// ✅ Good - descriptive
it('should return empty array when no users found')
it('should throw ValidationError when email is invalid')

// ❌ Bad - vague
it('works correctly')
it('handles error')
typescript
// ✅ Good - descriptive
it('should return empty array when no users found')
it('should throw ValidationError when email is invalid')

// ❌ Bad - vague
it('works correctly')
it('handles error')

References

参考资料