驗收測試 - 重新思考 Rails 架構
在實際開始實作之前,透過測試確認行為以及開發過程中進行驗證都會是個不錯的方式。我們會透過 Cucumber 的文件測試法中的方式,來描述一個運送狀態更新的設計。
描述功能
假設我們要實現一個跨時區的物流運送流程,那麼可以撰寫如下的測試。
1Feature: Shipment
2 Scenario: I can update the simpment route
3 Given there have some shipment
4 | id | state |
5 | 1 | shipping |
6 And there have some shipment route
7 | route_id | shipment_id | delivered_at |
8 | OKA | 1 | 2024-03-19T00:00:00Z |
9 When I make a POST request to "/shipments/1/routes"
10 """
11 {
12 "route_id": "TPE",
13 "date": "0319",
14 "time": "1000"
15 }
16 """
17 Then the response should be
18 """
19 {
20 "id": 1,
21 "state": "shipping",
22 "routes": [
23 {
24 "route_id": "OKA",
25 "shipment_id": 1,
26 "delivered_at": "2024-03-19T00:00:00.000Z"
27 },
28 {
29 "route_id": "TPE",
30 "shipment_id": 1,
31 "delivered_at": "2024-03-19T02:00:00.000Z"
32 }
33 ]
34 }
35 """
上面的例子我們透過描述 API 的行為,來呈現一些資訊。
- 運送狀態是對應某筆訂單
- 運送過程會有多個路徑(Route)
- 填入時間時,會以
date
和time
的格式搭配,並且以當地時間為基準
除此之外,在系統的設計中我們預期 Order 和 Shipment 是一對一的關係,因此在這裡不會有 order_id
的欄位,從實體(Entity)的角度來看辨識 Order 和辨識 Shipment 是相同的。
然而,在 Route 的觀點來看,一個實體會是 Shipment ID + Route ID 的組合,上述的情境中我們仍可以使用資料庫的 Auto Increment 機制來管理,然而在實際使用時不一定會直接參考資料庫的流水號。
針對回傳內容的檢查,因為完整比對 JSON 有時候不一定是個好的處理方式,可以考慮利用 JMESPath 這類套件,使用
routes[0].route_id
來找到OKA
進行比對,會相對有彈性
步驟定義
有了測試的步驟後,就可以來撰寫步驟定義。
1Given('there have some shipment') do |table|
2 table.hashes.each do |row|
3 Shipment.create!(**row)
4 end
5end
6
7Given('there have some shipment route') do |table|
8 table.hashes.each do |row|
9 ShipmentRoute.create!(**row)
10 end
11end
12
13When('I make a POST request to {string}') do |path, raw_body|
14 body = JSON.parse(raw_body)
15 @response = post path, body
16end
17
18Then('the response should be') do |raw_body|
19 expected = JSON.parse(raw_body)
20 actual = JSON.parse(@response.body)
21
22 expect(actual).to eq(expected)
23end
我們直接透過 ActiveRecord 定義的 Model 來生成測試用的資料,並且直接對回傳的內容轉換成 JSON 進行比對,這樣就可以有初步的雛形。
實際開發時會盡可能推遲 Model 層級的實作,因為這系列的重點不在測試的實作,因此會跳過比較多細節。
接下來就可以切入到 Controller 的部分來進行實作,至於測試案例可以根據情況在這個階段多描述並以 @wip
標記註記會在之後處理,或者在後續開發時有發現新的案例時補上。
如果對這篇文章有興趣,可以透過以下連結繼續閱讀這系列的其他文章。
- 軟體架構的挑戰 - 重新思考 Rails 架構
- 資料驅動設計 - 重新思考 Rails 架構
- 複雜的操作 - 重新思考 Rails 架構
- 時區換算 - 重新思考 Rails 架構
- 報表機制 - 重新思考 Rails 架構
- 通用化功能 - 重新思考 Rails 架構
- ActiveRecord 的限制 - 重新思考 Rails 架構
- 領域驅動設計 - 重新思考 Rails 架構
- 從架構到設計 - 重新思考 Rails 架構
- 重復使用的反思 - 重新思考 Rails 架構
- 釐清脈絡 - 重新思考 Rails 架構
- 劃分邊界 - 重新思考 Rails 架構
- 職責劃分 - 重新思考 Rails 架構
- 架構規劃 - 重新思考 Rails 架構
- 驗收測試 - 重新思考 Rails 架構
- Controller - 重新思考 Rails 架構
- Form - 重新思考 Rails 架構
- Use Case - 重新思考 Rails 架構
- Entity - 重新思考 Rails 架構
- Repository - 重新思考 Rails 架構
- Output - 重新思考 Rails 架構
- Query - 重新思考 Rails 架構
- 可能性 - 重新思考 Rails 架構