阿里云主机折上折
  • 微信号
Current Site:Index > Unit testing specification

Unit testing specification

Author:Chuan Chen 阅读数:64396人阅读 分类: 前端综合

Unit testing is a crucial means of ensuring code quality. Through standardized unit testing practices, defects can be effectively reduced, and code maintainability can be improved. In the frontend domain, the diverse technology stack requires unit testing to be tailored to framework features and business scenarios.

Core Value of Unit Testing

Unit testing verifies the smallest testable units of code, typically functions or class methods. Well-designed unit testing offers three key benefits:

  1. Rapid Feedback: Immediately validates logic correctness after code changes, significantly improving efficiency compared to manual testing.
  2. Design Improvement: Writing tests naturally encourages code decoupling and enhances modularity.
  3. Documentation Role: Test cases serve as living documentation for code behavior.
// Example: Testing pure functions
function add(a, b) {
  return a + b
}

describe('add function', () => {
  it('should return 5 when adding 2 and 3', () => {
    expect(add(2, 3)).toBe(5)
  })
  
  it('should handle negative numbers', () => {
    expect(add(-1, -1)).toBe(-2)
  })
})

Frontend Unit Testing Framework Selection

Mainstream frontend testing frameworks have distinct focuses:

  • Jest: A zero-configuration solution by Facebook, featuring built-in assertion libraries and coverage tools.
  • Vitest: A Vite-based ultra-fast testing solution compatible with Jest syntax.
  • Mocha + Chai: A flexible combination suitable for highly customized scenarios.
// Vitest example
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import Button from './Button.vue'

describe('Button Component', () => {
  it('renders slot content', () => {
    const wrapper = mount(Button, {
      slots: { default: 'Click Me' }
    })
    expect(wrapper.text()).toContain('Click Me')
  })
})

Test Coverage Standards

Coverage metrics should include:

  1. Line Coverage: At least 80%.
  2. Branch Coverage: All conditional branches must be tested.
  3. Function Coverage: All exported functions should be tested.

Configure thresholds via .nycrc:

{
  "check-coverage": true,
  "lines": 80,
  "branches": 75,
  "functions": 85,
  "statements": 80
}

Best Practices for Component Testing

UI component testing should focus on:

  1. Rendering Verification: Check DOM structure and style classes.
  2. Interaction Testing: Simulate user-triggered events.
  3. Props Validation: Test behavior under different prop combinations.
// React component testing example
import { render, screen, fireEvent } from '@testing-library/react'
import Toggle from './Toggle'

test('toggles state when clicked', () => {
  render(<Toggle />)
  const button = screen.getByRole('switch')
  
  expect(button).toHaveAttribute('aria-checked', 'false')
  fireEvent.click(button)
  expect(button).toHaveAttribute('aria-checked', 'true')
})

Patterns for Asynchronous Code Testing

Three approaches to handle asynchronous logic:

  1. Callback Detection: Use the done parameter.
  2. Promise Return: Let the testing framework wait automatically.
  3. Async/Await: The most intuitive modern approach.
// Asynchronous testing example
describe('fetchUser API', () => {
  it('resolves with user data', async () => {
    const user = await fetchUser(123)
    expect(user).toHaveProperty('id', 123)
  })

  it('rejects when user not found', () => {
    await expect(fetchUser(999)).rejects.toThrow('Not Found')
  })
})

Test Data Management Strategies

Test data organization directly impacts maintainability:

  1. Factory Functions: Dynamically generate test data.
  2. Fixed Fixtures: Store static data in JSON files.
  3. Random Data: Use faker.js to generate realistic data.
// Factory function example
const createProduct = (overrides = {}) => ({
  id: faker.datatype.uuid(),
  name: faker.commerce.productName(),
  price: faker.commerce.price(),
  ...overrides
})

describe('Shopping Cart Logic', () => {
  it('should calculate total price including item prices', () => {
    const cart = {
      items: [createProduct({ price: 100 }), createProduct({ price: 200 })]
    }
    expect(calculateTotal(cart)).toBe(300)
  })
})

Test Performance Optimization

Speed-up solutions for large projects:

  1. Parallel Execution: Use Jest's --maxWorkers parameter.
  2. File Filtering: Run only tests related to modified files.
  3. Mock Optimization: Replace full implementations with lightweight mocks.
# Parallel test execution
jest --maxWorkers=4

# Run only tests related to modified files
jest --onlyChanged

Testing in Continuous Integration

Key CI pipeline configurations:

  1. Caching Strategy: Cache node_modules and Jest cache directories.
  2. Phased Execution: Separate unit tests from E2E tests.
  3. Failure Retry: Automatically retry flaky tests.
# GitHub Actions example
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/cache@v3
        with:
          path: |
            **/node_modules
            **/.jest-cache
          key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
      
      - run: yarn test:unit --ci --runInBand

Avoiding Common Anti-Patterns

Testing practices to avoid:

  1. Over-Implementation Verification: Testing internal logic instead of behavior.
  2. Fragile Selectors: Relying on DOM structure instead of semantic attributes.
  3. Global State Leaks: Failing to reset state between tests.
// Anti-pattern example: Testing implementation details
test('should not test internal state directly', () => {
  const instance = new Component()
  expect(instance._internalState).toBe(0) // Bad practice
  
  // Should test public behavior instead
  instance.doSomething()
  expect(instance.getResult()).toBe(1)
})

Principles for Maintaining Test Code

Key points for keeping test code quality high:

  1. DRY Principle: Reuse common logic via setup functions.
  2. Clear Descriptions: Test descriptions should include expected behavior and context.
  3. Layered Organization: Structure test files by functional domains.
// Test organization example
src/
  components/
    Button/
      Button.tsx
      Button.test.tsx  # Unit tests
      Button.stories.tsx  # Visual cases
  utils/
    math.test.ts  # Pure function tests

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:静态代码检查

下一篇:集成测试规范

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.