ISA後端指令
EntityValidate
驗證資料庫記錄的存在性與正確性
EntityValidate 讓你直接在 Gherkin 中驗證資料庫狀態,確保資料真正寫入或更新而非只是 API 回傳正確。
基本用法
Then 應該存在一個待辦事項, with table:
| todoId | userId | title | completed |
| $todo1.id | $Alice.id | 買牛奶 | false |這段指令會:
- 透過 Entity Spec 將「待辦事項」對應到
todos資料表,並取得欄位定義 - 以
todoId作為主鍵查詢資料表 - 逐欄位驗證實際值是否符合預期
為什麼需要驗證資料庫?
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": >(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 | 手機 | >(10000) | <e(1000) | &isNull |常用約束:
&isNum、&isStr、&isNull— 型別檢查>()、<()、>e()、<e()、&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") |