March 15, 2025

前端測試指南 - 策略與實踐 (Chapter 2-4 ~ 2~6)


測試實作 / 測試行為

<Counter /> 組件去顯示時

實作部分, 通常代表 increment decrement 的行為差異 確保 +1 -1 的實作正確無誤.

行為部分, 著重在 {count} 變數在畫面上的數值變化是否如預期

import React, { Component } from "react";

class Counter extends Component {
  state = { count: 0 };

  increment = () => {
    this.setState({ count: this.state.count + 1 });
  };

  decrement = () => {
    this.setState({ count: this.state.count - 1 });
  };

  render() {
    return (
      <div>
        <h2>Class Counter</h2>
        <p>Count: {this.state.count}</p>
        <button onClick={this.increment}>+</button>
        <button onClick={this.decrement}>-</button>
      </div>
    );
  }
}

export default Counter;
import React, { useState } from "react";

const Counter: React.FC = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h2>Function Counter</h2>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
    </div>
  );
};

export default Counter;

可以透過 class 寫出的實作測試, 接續做出 function 的重構


商業邏輯與資料的分離是 function components 的好處, 將特定業務邏輯分離成 custom hooks, 並將畫面顯示的部份留給 UI 組件, 這同時也是現在流行的測試方式

React Testing Library 測試行為的做法會比 Enzyme 著重於測試實作的方式來得更主流


React Testing Library vs. Enzyme

React Testing Library(行為導向測試)

Enzyme(實作導向測試)

🔹 結論


淺渲染 (shallow rendering)

元件渲染方式, 只對元件本身渲染

為什麼不推薦使用淺渲染?

[!WARNING] react-test-renderer 已經暫停維護了 @testing-library/react 目前主要使用這個 clipboard.png Migrate from Enzyme | Testing Library RTL 說明盡可能避免如果真的需要則使用 jest.mock 做模擬。


完全渲染 (full rendering)

顧名思義, 目的是可以測試組件的完整行為, 但會增加測試的複雜度, 適合 integration tests.

import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';

test('renders MyComponent with all state and effects', () => {
  render(<MyComponent />);

  // 假設 MyComponent 包含一個按鈕,點擊它會改變顯示的文本
  const button = screen.getByRole('button');
  const text = screen.getByText(/hello world/i);

  expect(text).toBeInTheDocument(); // 初次渲染文本
  button.click();

  const updatedText = screen.getByText(/goodbye world/i);
  expect(updatedText).toBeInTheDocument(); // 渲染後的文本

  // 這就是一次完整的渲染過程,涵蓋了狀態改變、事件觸發及更新
});

Full Rendering vs Shallow Rendering 的比較

特點Full RenderingShallow Rendering
渲染的深度渲染組件及所有子組件只渲染組件本身,子組件不會被渲染
副作用執行執行所有副作用(例如 useEffectcomponentDidMount 等)不會執行子組件的副作用
渲染真實 DOM渲染到真實的 DOM 中,可以進行交互不會將子組件渲染到 DOM 中,僅是虛擬 DOM 渲染
測試範圍測試組件的所有行為及其與子組件的交互測試組件本身的行為,不測試子組件的行為
測試速度較慢,因為需要渲染整個組件樹較快,因為只渲染組件本身
測試場景測試組件與其子組件的協作及交互,適合集成測試測試組件的邏輯、方法和狀態,適合單元測試