自動化測試基本上只是程式碼,會在下列情況下擲回或導致錯誤: 發生問題大部分的程式庫或測試架構都提供 可更輕鬆地編寫測試的基本功能。
如上一節所述,這些基元通常都包含一個 定義獨立測試 (稱為測試案例) 並提供 斷言。斷言是一種結合檢查結果和擲回 並視為 以及測試基元
本頁說明這些基元的通用做法。您選擇的架構 可能有類似的內容,但並非確切的參考值
例如:
import { fibonacci, catalan } from '../src/math.js';
import { assert, test, suite } from 'a-made-up-testing-library';
suite('math tests', () => {
test('fibonacci function', () => {
// check expected fibonacci numbers against our known actual values
// with an explanation if the values don't match
assert.equal(fibonacci(0), 0, 'Invalid 0th fibonacci result');
assert.equal(fibonacci(13), 233, 'Invalid 13th fibonacci result');
});
test('relationship between sequences', () => {
// catalan numbers are greater than fibonacci numbers (but not equal)
assert.isAbove(catalan(4), fibonacci(4));
});
test('bugfix: check bug #4141', () => {
assert.isFinite(fibonacci(0)); // fibonacci(0) was returning NaN
})
});
這個範例會建立一組稱為「數學」的測試 (有時也稱為套件) 測試」,並定義三個獨立測試案例,每個案例都會執行一些斷言。 這些測試案例通常可以個別處理或執行,例如 在測試執行工具中 建立篩選器旗標
做為斷言輔助工具
大部分的測試架構,包括 Vitest 都提供一組斷言
assert
物件的輔助程式,可讓您快速檢查回傳值或
不符合某些期望的狀態。預期情況通常為「已知良好」
輕鬆分配獎金在前一個範例中,我們知道 13 個費波那契數必須是
233,方便我們直接使用 assert.equal
確認。
您可能也會預期價值會採特定形式, 或其他屬性。這堂課程不會 涵蓋所有可能的斷言輔助程式,不過測試架構 一律提供下列基本檢查:
'truthy' 通常被認為是「確定」並檢查條件是否為 True 您會如何編寫
if
來檢查事物是否成功 正確。通常以assert(...)
或assert.ok(...)
提供。 就會接受單一值和選填註解。等式檢查 (例如數學測試範例中) 傳回物件的值或狀態,等於已知的良好值。適用對象 基本等式 (例如數字和字串) 或參照等式 (這些是同一個物件)。但其實這些只是「趨勢」確認 與
==
或===
比較。- JavaScript 會區分鬆散 (
==
) 和嚴格 (===
) 等式。 大多數測試程式庫都提供方法assert.equal
和assert.strictEqual
。
- JavaScript 會區分鬆散 (
深度品質檢查,將品質檢查延伸為包含檢查 物件、陣列的內容以及其他較複雜的資料類型, 內部邏輯來掃遍物件來進行比較。重要的是 因為 JavaScript 並沒有內建 兩個物件或陣列例如,
[1,2,3] == [1,2,3]
一律為 false。測試 架構通常包含deepEqual
或deepStrictEqual
輔助程式。
比較兩個值的宣告輔助程式 (而非僅限「truthy」檢查) 通常會使用兩個或三個引數:
- 由測試中程式碼產生的實際值,或是描述 待驗證的狀態。
- 預期的值,通常使用硬式編碼 (例如 字串)。
- 選填註解,描述預期狀況或失敗情形 如果這一行失敗,列就會納入其中。
我們也相當常見的做法是結合斷言結合斷言 再次檢查,因為很少能夠正確確認 基礎架構例如:
test('JWT parse', () => {
const json = decodeJwt('eyJieSI6InNhbXRob3Ii…');
assert.ok(json.payload.admin, 'user should be admin');
assert.deepEqual(json.payload.groups, ['role:Admin', 'role:Submitter']);
assert.equal(json.header.alg, 'RS265')
assert.isAbove(json.payload.exp, +new Date(), 'expiry must be in future')
});
Vitest 使用 Chai 斷言程式庫 內部提供斷言輔助程式 因此查看 ,瞭解何種斷言和輔助程式可能適用於您的程式碼。
Fluent 和 BDD 斷言
有些開發人員偏好使用行為導向的斷言樣式
開發 (BDD),或
流利風格
斷言。也稱為「預期」因為這個進入點
檢查預期是一種名為 expect()
的方法。
預期輔助程式的行為與以簡單方法寫成的斷言相同
呼叫 assert.ok
或 assert.strictDeepEquals
,但有些開發人員覺得它們更容易閱讀。
BDD 斷言可能如下所示:
// A failure here would generate "Expect result to be an array that does include 42"
const result = await possibleMeaningsOfLife();
expect(result).to.be.an('array').that.does.include(42);
// or a simpler form
expect(result).toBe('array').toContainEqual(42);
// the same in assert might be
assert.typeOf(result, 'array', 'Expected the result to be an array');
assert.include(result, 42, 'Expected the result to include 42');
這類斷言的運作方式,在於一種稱為方法鏈結的技術
其中 expect
傳回的物件可與
進階方法呼叫通話的部分環節,包括 to.be
和 that.does
上述範例不含任何函式,只會用於發出呼叫
更容易閱讀;如果測試,則可能會產生自動留言
失敗。(請注意,expect
通常不支援選擇性註解,因為
鏈結應清楚描述失敗情形)
許多測試架構都支援 Fluent/BDD 和一般斷言。Vitest, 例如,匯出 Chai 採用的做法,對 BDD 採取略為簡潔的做法。Jest、 另一方面,如果包含 預期 method。
跨檔案將測試分組
編寫測試時,我們通常已經提供隱含的分組方式,而非 比起在單一檔案中所有的測試中,編寫多個測試是很常見的情況 檔案。事實上,測試執行者通常只會知道檔案僅供測試,因為 預先定義的篩選器或規則運算式,例如 vitest 檔案中結尾為「.test.jsx」等副檔名的檔案或「.spec.ts」 (「.test」和「.spec」加上多個有效副檔名)。
元件測試通常位於受測試元件的對等檔案中。 如以下目錄結構所示:
同樣地,單元測試通常位於受測試的程式碼附近。 端對端測試可能會位於各自的檔案中,而整合測試 放在自己專屬的資料夾中您可以運用這些結構 不斷拓展複雜的測試案例,需要自己的非測試支援檔案,例如 測試所需的支援資料庫
在檔案中將測試分組
和前面的例子一樣,一般做法是將測試放入呼叫
suite()
會將您使用 test()
設定的測試分組。套房通常不會有
但有助於將相關測試分組
呼叫傳遞的方法,或是設定目標如果是 test()
,傳遞的方法會說明
測試本身的動作
和斷言一樣,Fluent/BDD 中的 Fluent/BDD 同樣具有相當標準的標準 以便將測試分組以下程式碼中有一些常見範例的比較:
// traditional/TDD
suite('math tests', () => {
test('handle zero values', () => {
assert.equal(fibonacci(0), 0);
});
});
// Fluent/BDD
describe('math tests', () => {
it('should handle zero values', () => {
expect(fibonacci(0)).toBe(0);
});
})
在大多數架構中,suite
和 describe
的行為與 test
和
it
,相比之下,使用 expect
和 assert
的差異性較高
以便寫入斷言
其他工具則對於安排套件和測試的安排方式有細微差異。適用對象
例如,Node.js 內建測試執行器支援建立對 test()
的巢狀呼叫
間接建立測試階層不過,Vitest 規定
使用 suite()
建立巢狀結構,且不會執行另一個 test()
中定義的 test()
。
和斷言一樣,請記得 技術堆疊提供的方法並不重要。本課程將介紹 方便您瞭解它們如何應用到 這些工具
生命週期方法
將測試分組的理由之一,即使是隱式的頂層 為每次測試或一次執行一次 一組測試。多數架構提供四種方法:
針對每個 `test()` 或 `it()` | 一年一次 | |
---|---|---|
測試執行前 | 「beforeEvery()」 | `beforeAll()` |
測試執行後 | 「afterEach()」 | 「afterAll()」 |
舉例來說,您可以在每個虛擬使用者資料庫 測試,然後在結束後清除:
suite('user test', () => {
beforeEach(() => {
insertFakeUser('bob@example.com', 'hunter2');
});
afterEach(() => {
clearAllUsers();
});
test('bob can login', async () => { … });
test('alice can message bob', async () => { … });
});
這有助於簡化測試。您可以分享常用設定和 而不是每次測試都要複製一次此外, 「安裝」和「拆解」程式碼本身會擲回錯誤,表示結構 但不含測試本身失敗的問題
通用建議
思考這些基元時,以下提供幾個要點。
基本觀念可以當做參考
請記住,這些工具與基本功能,在接下來幾頁中不會有 完全符合 Vitest、Jest、Mocha 或 Web Test Runner 或其他任何項目 具體而言雖然我們是 Vitest 的一般指南,但請務必 搭配您選擇的架構
視需要混合及比對斷言
測試基本上就是可能會擲回錯誤的程式碼。每位跑者都會提供
基本 (可能是 test()
) 用來描述不同的測試案例。
但如果該執行器也會提供 assert()
、expect()
和斷言輔助程式,
別忘了,這部分比較方便好用,可以略過這個步驟
不需要手動操作您可以執行任何可能會擲回錯誤的程式碼,包括
斷言程式庫,或舊式的良好 if
陳述式。
IDE 設定能有效節省電力
確認 IDE (例如 VSCode) 可以存取自動完成功能,
,瞭解如何提升測試效率。適用對象
例如,assert
的 Chai 斷言中有超過 100 個方法
程式庫,並取得有關
以內嵌方式顯示註解是最方便的做法
這在部分填入 通用命名空間和測試方法這只是細微差異 您通常可以使用測試程式庫,不必匯入 會自動新增至全域命名空間:
// some.test.js
test('using test as a global', () => { … });
建議您「即使」系統支援自動支援的輔助程式,仍建議您匯入。
因為這樣您的 IDE 才能明確查詢這些方法。(您
會在建構 React 時遇到這個問題,因為部分程式碼集具有神奇
全域 React
,但有些則不支援,且需要透過以下方式在所有檔案中匯入:
React.)
// some.test.js
import { test } from 'vitest';
test('using test as an import', () => { … });