今天開始準備做後端的 API 囉~~~
我們同樣秉持測試驅動開發的精神,在還沒開始之前就先設計、撰寫測試,然後才是開發與重構。
程式碼請參考 D22/consumer-driven-contract
消費者驅動合約 ( consumer driven contract ),依照我的理解一言以蔽之就是
根據 API 被使用 的方式來定義文件並進行測試。
現在已經有工具例如
Pact.js
可以幫助大家實踐,有興趣的話可以參考看看。
接下來我們會參考它背後的理念來設計測試,因此我們要知道 API 如何被使用,而這其實就跟昨天的主題有關
// src\service\contracts\get-user.spec.ts
import ...
describe('GET /api/v1/users/:username', () => {
const baseUrl = 'http://localhost'
const server = setupServer()
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
describe('when exists user richard_00 to richard_99', () => {
beforeEach(() => {
server.use(
getUserHandler(baseUrl)('exists user richard_00 to richard_99')
)
})
it('should get a user when username is richard_01', async () => {
//arrange
const username = 'richard_01'
//act
const result = await pipe(
getUser(username),
Effect.merge,
Effect.runPromise
)
//assert
const data = S.parseSync(User.schema)(result)
expect(data.name).toBe(username)
})
it('should get not found error when username is richard_x', async () => {
//arrange
const name = 'richard_x'
//act
const result = await pipe(getUser(name), Effect.merge, Effect.runPromise)
//assert
expect(S.is(NotFoundError.struct)(result)).toBe(true)
})
})
it('should get unexpected axios error when internal error', async () => {
//arrange
server.use(getUserHandler(baseUrl)('database connection is broken'))
const name = 'richard_01'
//act
const result = await pipe(getUser(name), Effect.merge, Effect.runPromise)
//assert
expect(S.is(UnexpectedAxiosError.struct)(result)).toBe(true)
})
})
前端的單元測試會詳細的告訴你,它期待 API 有哪些行為,撇開可以避免的格式錯誤不談,以上測試內容可以轉換成以下合約
在存在使用者
richard_00
到richard_99
的狀態下
- 前端送出
GET /api/v1/users/richard_01
請求,會收到狀態碼 200 加上格式正確的使用者物件- 前端送出
GET /api/v1/users/richard_x
請求,會收到狀態碼 404在後端發生錯誤的情況下
- 前端送出
GET /api/v1/users/richard_01
請求,會收到狀態碼 500
上面的場景是最簡單的了,畢竟這就是單純的 GET 請求,沒有其他互動,所以相較於傳統基於 API 的測試沒有太大差異。
我們想像一個複雜點的場景
前端送出
POST /api/v1/courses/course123/users
請求,會收到 201 回應
在POST /api/v1/courses/course123/users
請求成功的狀態下接著送出GET /api/v1/courses
請求 ,會收到 200,而且回應的課程物件列表
裡面會有剛才新增的使用者物件
在這樣的場景下,相對單純的 API 測試,消費者驅動合約就能帶給我們更多的信心。