最近在準備明年(2024)的連載主題,在實作的時候意外發現自己逐漸習慣「不使用瀏覽器」的狀況下去進行開發,除了比較常用的後端情境之外,連前端也很順利的可以實踐這件事情。
測試驅動開發
一直到現在,我都很難實踐測試驅動開發。畢竟有非常多情況是很難適用的,例如在做 PoC(Proof of concept,概念驗證)的時候,還硬要寫測試是有點浪費時間,或者在對需求很不確定時也只能硬著頭皮做看看。
如果在需求足夠明確的狀況下,要實現這件事情就沒有預想中的困難。但這也不表示所有的開發過程都要先寫測試,採用 ATDD(Acceptance test-driven development,驗收測試驅動開發)的方式更為適合。
簡單來說,就是我們以「想要的成果」當作前提撰寫測試,並且順著這些測試來實作。在過程中會不斷的重構出新的元件或模組,他們的測試可能是在重構(Refactoring)的過程中實現,不一定會在初期完成。
舉個例子,像是我在後端預期有一個這樣的 API 回應:
1{
2 "data": [
3 { "id": 1, "done": true, "description": "write article" }
4 ]
5}
那麼我可以先寫一段測試驗證,可以用 Cucumber、RSpec、Vitest 等等各種測試框架來實現。
1RSpec.describe 'GET /todos' do
2 # ...
3 subject { get todos_path }
4
5 it { is_expected.to include(/"data": \[/) }
6 it { is_expected.to include(/"id": 1/) }
7 # ...
8 # or customize matcher to verify response
9end
在這個階段,我們可以會有一些 Controller、Model 之類的物件被實現,但是我們還不需要去撰寫相關的單元測試(Unit Test)只需要先關注在這個功能的輸入與輸出即可。
前端的目標
這幾年對 OKR(Objective Key-Result)的概念比較熟悉後,會發在軟體產業的產品開發,不外乎就是去實現滿足使用者需求的功能,那麼在 ATDD 的思考方式下,我們只需要關注「如何使用達成目的」這樣的目標即可。
假設我們要製作一個計算機,可能會有一份這樣的 User Story(使用者故事,描述使用者的一系列動作)這裡直接使用 Cucumber 的 Gherkin 格式撰寫,現實狀況可能更像一段文章。
1#language:zh-TW
2功能: 計算機
3 場景: 蒼時可以透過點選 1 + 1 獲得 2 的結果
4 當 點選按鈕 "1"
5 並且 點選按鈕 "+"
6 並且 點選按鈕 "1"
7 並且 點選按鈕 "C"
8 那麼 可以看到 "2" 作為結果
這裡描述了一個加法計算的情況,並且詳細的描述我們從使用者故事中提取出來的「預期操作」來反應這件事情,最終的目標是有一段程式能實現這件事情。
過去我會覺得這樣的測試非常難以處理,主要是在環境準備的過程中有不少條件需要滿足。在準備文章一開始提到明年的連載時,也是在這個階段摸魚了一段時間才開始。然而,現在有非常多容易使用的工具,我們可以很輕鬆的實現這件事情。
用 Playwright 實現
選用 Playwright 的理由是我用起來覺得蠻順手的,如果習慣使用像是 Cypress 這類工具也完全沒問題。
我們這邊直接以 Playwright 的方式撰寫測試,如何跟 Cucumber 搭配就請期待我在 2024 年的新連載系列。
1import { test, expect } from '@playwright/test';
2
3test('aotoki can calculate 1 + 1', async ({ page }) => {
4 await page.getByRole('button', { name: '1' }).click()
5 await page.getByRole('button', { name: '+' }).click()
6 await page.getByRole('button', { name: '1' }).click()
7 await page.getByRole('button', { name: 'C' }).click()
8
9 await expect(page.getByTestId('result')).toHaveText('2')
10});
上面這段測試程式,跟 Cucumber 描述的行為是完全一致,也就是說只要我們能在我們的前端實作中符合這些條件,那麼就可以實現這個功能,而這個功能在開發過程中是不需要「在瀏覽器測試」的。
以這個案例,我們是無法驗證有 1 以外的按鈕,因此我們可以繼續改善測試的描述。
1#language:zh-TW
2功能: 計算機
3 場景: 蒼時可以透過點選 1 + 1 獲得 2 的結果
4 當 點選按鈕 "<btn1>"
5 並且 點選按鈕 "<btn2>"
6 並且 點選按鈕 "<btn3>"
7 並且 點選按鈕 "C"
8 那麼 可以看到 "<res>" 作為結果
9 例子:
10 | btn1 | btn2 | btn3 | res |
11 | 1 | + | 1 | 2 |
12 | 2 | + | 3 | 5 |
13 # ...
這件事情有幾個面向可以思考:
- 使用者真的需要 2 ~ 9 的按鈕嗎?
- 在目前這個階段有需要嗎?
因為不是這篇文章的重點,就留給大家思考。直到我們的功能完善後,我們在何時需要瀏覽器呢?主要就是「切版」的任務,這件事情有可能是由設計團隊負責,像是 Design System(設計系統)這樣的東西。
不論如何,假設我們試著將「畫面呈現」的因素排除專注在功能上,在需要處理「視覺」問題之前,也許都不需要使用瀏覽器輔助。
切版某種程度上也能做到自動化,然而要追求到精確的符合設計稿難度實在太高,我認為乖乖打開瀏覽器還是比較實用的方式。