整潔測試:FIRST 與 AAA (Clean Tests)

★★★★Draft

FromClean Code

📚 From the Books

整潔測試:FIRST 與 AAA (Clean Tests)Testing

測試程式碼和產品程式碼一樣重要——骯髒的測試比沒有測試更糟,因為它會隨系統演進而腐爛,最後成為改動的絆腳石。整潔測試只有一個衡量標準:可讀性。一個好測試該像一則小故事,讓人一眼看穿「它在測什麼、期待什麼」。

🧠 Why It Matters

NOTE

FIRST 五律Fast(夠快才會常跑)、Independent(測試互不依賴,才能精準定位失敗)、Repeatable(任何環境都能重跑)、Self-Validating(只回傳 Pass/Fail)、Timely(在產品碼之前寫,即 TDD)。

⚖️ Case Study

前 — 一個測試測了三件事,結構糊成一團
test("cart works", () => {
  const cart = new Cart();
  cart.addItem({ name: "Apple", price: 10 });
  expect(cart.total()).toBe(10); // 測了「新增」
  cart.removeItem("Apple");
  expect(cart.total()).toBe(0); // 又測了「移除」
  cart.applyCoupon("SAVE5");
  cart.addItem({ name: "Book", price: 20 });
  expect(cart.total()).toBe(15); // 還測了「折價券」
});

名字 cart works 什麼都沒說;中間任一 expect 失敗,你都得回頭讀整段才知道壞在哪。三個概念擠在一個測試裡。

後 — 一概念一測試,AAA 三段分明
test("adding an item increases the total by its price", () => {
  const cart = new Cart(); // Arrange
  cart.addItem({ name: "Apple", price: 10 });
  const total = cart.total(); // Act
  expect(total).toBe(10); // Assert
});

test("removing the only item brings the total back to zero", () => {
  const cart = new Cart();
  cart.addItem({ name: "Apple", price: 10 });
  cart.removeItem("Apple");
  expect(cart.total()).toBe(0);
});

test("a coupon discounts the total by its value", () => {
  const cart = new Cart();
  cart.addItem({ name: "Book", price: 20 });
  cart.applyCoupon("SAVE5");
  expect(cart.total()).toBe(15);
});

每個測試名字就是一句規格,失敗時直接告訴你哪個概念壞了;三段 Arrange-Act-Assert 讓故事一目了然。

WARNING

別為了「省事」把斷言全塞進一個測試。測試的價值在失敗時能不能立刻定位問題;一個測十件事的測試失敗時,等於什麼都沒告訴你。

🔑 Takeaways

✍️ My Notes

No notes yet — jot your takeaways or Q&A here.

📖 Further Reading