SpecFormula AI
ISA後端指令

EntityValidate

驗證資料庫記錄的存在性與正確性

EntityValidate 讓你直接在 Gherkin 中驗證資料庫狀態,確保資料真正寫入或更新而非只是 API 回傳正確。

基本用法

Then 應該存在一個待辦事項, with table:
  | todoId    | userId    | title  | completed |
  | $todo1.id | $Alice.id | 買牛奶 | false     |

這段指令會:

  1. 透過 Entity Spec 將「待辦事項」對應到 todos 資料表,並取得欄位定義
  2. todoId 作為主鍵查詢資料表
  3. 逐欄位驗證實際值是否符合預期

為什麼需要驗證資料庫?

ResponseValidate 只驗證 API 回應,無法確認資料是否真正寫入資料庫:

# API 回應可能正確,但資料庫可能沒寫入
Then 新增待辦事項(201)回應, with table:
  | todoId    | title  |
  | $todo1.id | 買牛奶 |

# 直接查資料庫,確保資料持久化正確
And 應該存在一個待辦事項, with table:
  | todoId    | title  |
  | $todo1.id | 買牛奶 |

與 Entity Spec 的對應關係

EntityValidate 指令透過 Entity Spec 將業務實體名稱對應到實際的資料表,並根據 DDL 驗證欄位是否存在。

# entity_to_table_mapping.yml
entity_to_table_mapping:
  - 使用者: users
  - 待辦事項: todos
-- schema.sql
CREATE TABLE todos (
    todo_id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT NOT NULL,
    title VARCHAR(200) NOT NULL,
    completed BOOLEAN DEFAULT FALSE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Then 應該存在一個待辦事項, with table:
  | todoId    | title  |
  | $todo1.id | 買牛奶 |

# SpecFormula 自動對應到 todos 資料表
# SELECT * FROM todos WHERE todo_id = ?
# 驗證 title == "買牛奶"
Gherkin 元素對應來源
待辦事項entity_to_table_mapping 的 key
todos 資料表entity_to_table_mapping 的 value
todoId, title 欄位DDL 欄位定義

JSON DocString 格式

使用 with json: 搭配 """json ... """ 驗證 JSON 類型欄位的結構與值:

Then 應該存在一個訂單, with json:
  """json
  {
    "id": $order1.id,
    "orderItems": [
      { "productId": 5, "quantity": 2 },
      { "productId": 6, "quantity": 10 }
    ]
  }
  """

搭配 Symbol System:

Then 應該存在一個訂單, with json:
  """json
  {
    "id": $order1.id,
    "orderNo": &startsWith("ORD-"),
    "createdAt": &sameTime("2026-01-27T10:00:00"),
    "orderItems": [
      { "productId": $productId, "quantity": &gt(0) }
    ]
  }
  """

JSON 格式注意事項:符號系統的表達式($變數、&CAS 約束、@時間符號)不可放在 JSON 字串引號 "" 內,否則會被視為純字串。

Key 含 . 的逃脫語法

當 JSON key 本身包含 . 字元時,使用 ["..."] bracket notation 避免被誤拆為多層巢狀:

Then 應該存在一個設定, with table:
  | id | content.["btn.save"] | content.["btn.cancel"] |
  | 1  | 儲存                  | 取消                    |

JSON DocString 中直接使用原始 key,框架自動處理逃脫。

查找策略

EntityValidate 支援三種查詢方式:

1. PK 查詢(優先)

提供完整主鍵,直接以 PK 查詢單筆記錄:

| todoId    | title  |
| $todo1.id | 買牛奶 |

# SELECT * FROM todos WHERE todo_id = ?
# 驗證 title == "買牛奶"

2. Probe 查詢

缺少 PK 時,使用提供的欄位組合作為查詢條件:

| userId    | status | title  |
| $Alice.id | ACTIVE | 買牛奶 |

# SELECT * FROM todos WHERE user_id = ? AND status = ? AND title = ?
# 預期回傳恰好一筆

3. CAS 後過濾

Probe 回傳多筆結果時,用 CAS 約束在結果集中篩選唯一記錄:

| userId    | status | createdAt                        |
| $Alice.id | ACTIVE | &sameTime("2026-01-27T10:00:00") |

# SELECT * FROM todos WHERE user_id = ? AND status = ?
# 對結果集逐筆比對 created_at ≈ "2026-01-27T10:00:00"

型別轉換

框架自動進行語義比較:

比較類型說明
數值50000.00 == 50000(精度安全比較)
時間截斷至秒,忽略毫秒差異

CAS 約束

驗證時可使用 CAS 約束進行彈性驗證:

Then 應該存在一個商品, with table:
  | id | name | price      | stock      | deletedAt |
  | 1  | 手機 | &gt(10000) | &lte(1000) | &isNull   |

常用約束:

  • &isNum&isStr&isNull — 型別檢查
  • &gt()&lt()&gte()&lte()&between() — 數值範圍
  • &contains()&startsWith() — 字串匹配
  • &sameTime() — 時間比對
  • &oneOf() — 列舉匹配

完整約束清單請參考 CAS 符號

錯誤處理

Lint 階段

錯誤說明
Entity 未定義entity_to_table_mapping 中找不到
欄位不存在欄位在資料表定義中找不到

執行階段

錯誤說明
記錄不存在查詢結果為空
欄位值不匹配欄位值與預期不符
多筆結果Probe 回傳多筆且無法篩選唯一

完整範例

Feature: 新增待辦事項

  Background:
    Given 現在時間為 "2026-01-27T10:00:00"

    # EntitySetup 指令(參見 EntitySetup 文件)
    Given 準備一個使用者, with table:
      | >Alice.id | name  | email             | status |
      | <userId   | Alice | alice@example.com | ACTIVE |

  Example: 驗證待辦事項寫入資料庫

    # ApiCall 指令(參見 ApiCall 文件)
    When (UID="$Alice.id") 新增待辦事項, call table:
      | >todo1.id | title  | description |
      | <todoId   | 買牛奶 | 去全聯買    |

    # ResponseValidate 指令(參見 ResponseValidate 文件)
    Then 新增待辦事項(201)回應, with table:
      | todoId    | title  |
      | $todo1.id | 買牛奶 |

    # EntityValidate 指令 — 驗證資料庫記錄
    # 以 PK 查詢後逐欄位比對,&sameTime 為 CAS 約束
    And 應該存在一個待辦事項, with table:
      | todoId    | userId    | title  | description | completed | createdAt                        |
      | $todo1.id | $Alice.id | 買牛奶 | 去全聯買    | false     | &sameTime("2026-01-27T10:00:00") |

目錄