每當你想要確保你的UI不會有意外的改變,快照測試是非常有用的工具。
典型的快照測試用例呈現(xiàn) UI 組件,拍攝快照,然后將其與存儲在測試旁邊的參考快照文件進行比較。如果兩個快照不匹配,則測試將失?。焊氖且馔獾?,或者參考快照需要更新到新版本的 UI 組件。
在測試 React 組件時可以采用類似的方法。你可以使用測試渲染器為你的 React 樹快速生成可序列化的值,而不是渲染需要構(gòu)建整個應(yīng)用程序的圖形 UI??紤]Link組件的這個例子測試:
import React from 'react';
import renderer from 'react-test-renderer';
import Link from '../Link.react';
it('renders correctly', () => {
const tree = renderer
.create(<Link page="http://www.facebook.com">Facebook</Link>)
.toJSON();
expect(tree).toMatchSnapshot();
});
第一次運行此測試時,Jest 創(chuàng)建一個如下所示的快照文件:
exports[`renders correctly 1`] = `
<a
className="normal"
rel="external nofollow" target="_blank"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
</a>
`;
快照工件應(yīng)與代碼更改一起提交,并作為代碼審查過程的一部分進行審查。在代碼審查期間,Jest 使用友好的格式使快照更易于閱讀。在后續(xù)的測試運行中,Jest 會將渲染的輸出與之前的快照進行比較。如果它們匹配,則測試將通過。如果它們不匹配,則測試運行程序在您的代碼中發(fā)現(xiàn)了一個應(yīng)該修復(fù)的錯誤(在本例中,它是?<Link>
?組件),或者實現(xiàn)已更改并且快照需要更新。
注意:快照直接作用于呈現(xiàn)的數(shù)據(jù)——在我們的實例中,它是由?
<Link />
?的組件 page prop 傳遞給它。這也意味著即使任何其他文件在?<Link />
?組件中缺少 props (比如:?App.js
?)。它仍然可以通過測試,因為測試不知道?<Link />
?組件的用法,并且它的范圍僅限于 ?Link.react.js
?。此外,在其他快照測試中使用不同的 props 渲染相同的組件是不會影響第一個,因為測試不知道彼此。
有關(guān)快照測試如何工作以及我們?yōu)楹螛?gòu)建它的更多信息,請參閱發(fā)布博客文章。我們建議你閱讀這篇博文,以了解何時應(yīng)該使用快照測試。我們還建議你觀看有關(guān)使用 Jest 進行快照測試的蛋頭視頻。
在引入錯誤后,快照測試什么時候失敗是很容易被發(fā)現(xiàn)。發(fā)生這種情況時,請繼續(xù)解決問題并確保你的快照測試再次通過?,F(xiàn)在,讓我們談?wù)効煺諟y試由于有意的實現(xiàn)更改而失敗的情況。
如果我們有意更改示例中的 Link 組件指向的地址,就會出現(xiàn)這樣一種情況。
// Updated test case with a Link to a different address
it('renders correctly', () => {
const tree = renderer
.create(<Link page="http://www.instagram.com">Instagram</Link>)
.toJSON();
expect(tree).toMatchSnapshot();
});
在這種情況下,Jest 將打印以下輸出:
由于我們剛剛更新了我們的組件以指向不同的地址,因此期望該組件的快照發(fā)生變化是合理的。我們的快照測試用例失敗了,因為我們更新的組件的快照不再匹配這個測試用例的快照工件。
為了解決這個問題,我們需要更新我們的快照工件。你可以運行帶有標志的 Jest,該標志會告訴它重新生成快照:
jest --updateSnapshot
繼續(xù)并通過運行上述命令接受更改。?-u
?如果您愿意,您也可以使用等效的單字符標志來重新生成快照。這將為所有失敗的快照測試重新生成快照工件。如果由于意外錯誤導(dǎo)致我們有任何其他失敗的快照測試,我們需要在重新生成快照之前修復(fù)錯誤,以避免記錄錯誤行為的快照。
如果你想限制重新生成哪些快照測試用例,可以傳遞一個額外的?--testNamePattern
?標志來僅為那些與模式匹配的測試重新記錄快照。
你可以通過克隆快照示例、修改?Link
?組件和運行 Jest來嘗試此功能。
失敗的快照也可以在監(jiān)視模式下交互更新:
一旦你進入交互式快照模式,Jest 將一次一次地引導(dǎo)你完成失敗的快照,并讓你有機會查看失敗的輸出。
從這里你可以選擇更新該快照或跳到下一個:
完成后,Jest 會在返回觀看模式之前為你提供摘要:
內(nèi)聯(lián)快照的行為與外部快照(?.snap
?文件)相同,只是快照值會自動寫回到源代碼中。這意味著可以獲得自動生成快照的好處,而無需切換到外部文件以確保寫入了正確的值。
內(nèi)聯(lián)快照由Prettier提供支持。要使用內(nèi)聯(lián)快照,您必須已?prettier
?在項目中安裝。寫入測試文件時,您的 Prettier 配置將得到尊重。
如果您?prettier
?安裝在 Jest 找不到的位置,您可以使用"prettierPath"配置屬性告訴 Jest 如何找到它。
示例:
首先,編寫一個測試,?.toMatchInlineSnapshot()
?不帶參數(shù)調(diào)用:
it('renders correctly', () => {
const tree = renderer
.create(<Link page="https://prettier.io">Prettier</Link>)
.toJSON();
expect(tree).toMatchInlineSnapshot();
});
下次運行 Jest 時,?tree
?將進行評估,并將快照作為參數(shù)寫入?toMatchInlineSnapshot
?:
it('renders correctly', () => {
const tree = renderer
.create(<Link page="https://prettier.io">Prettier</Link>)
.toJSON();
expect(tree).toMatchInlineSnapshot(`
<a
className="normal"
rel="external nofollow" target="_blank"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
Prettier
</a>
`);
});
這里的所有都是它的!甚至可以?--updateSnapshot
?使用模式?u
?鍵或使用鍵來更新快照?--watch
?。
對象中通常有您想要生成快照的字段(如 ID 和日期)。如果你想嘗試對這些對象進行快照,它們將強制快照在每次運行時失?。?/p>
it('will fail every time', () => {
const user = {
createdAt: new Date(),
id: Math.floor(Math.random() * 20),
name: 'LeBron James',
};
expect(user).toMatchSnapshot();
});
// Snapshot
exports[`will fail every time 1`] = `
Object {
"createdAt": 2018-05-19T23:36:09.816Z,
"id": 3,
"name": "LeBron James",
}
`;
對于這些情況,Jest 允許為任何屬性提供非對稱匹配器。在寫入或測試快照之前檢查這些匹配器,然后將其保存到快照文件而不是接收到的值:
it('will check the matchers and pass', () => {
const user = {
createdAt: new Date(),
id: Math.floor(Math.random() * 20),
name: 'LeBron James',
};
expect(user).toMatchSnapshot({
createdAt: expect.any(Date),
id: expect.any(Number),
});
});
// Snapshot
exports[`will check the matchers and pass 1`] = `
Object {
"createdAt": Any<Date>,
"id": Any<Number>,
"name": "LeBron James",
}
`;
任何不是匹配器的給定值都將被準確檢查并保存到快照中:
it('will check the values and pass', () => {
const user = {
createdAt: new Date(),
name: 'Bond... James Bond',
};
expect(user).toMatchSnapshot({
createdAt: expect.any(Date),
name: 'Bond... James Bond',
});
});
// Snapshot
exports[`will check the values and pass 1`] = `
Object {
"createdAt": Any<Date>,
"name": 'Bond... James Bond',
}
`;
快照是識別應(yīng)用程序中意外界面更改的絕佳工具——無論該界面是 API 響應(yīng)、UI、日志還是錯誤消息。與任何測試策略一樣,為了有效地使用它們,你應(yīng)該了解一些最佳實踐以及應(yīng)該遵循的指南。
提交快照并作為常規(guī)代碼審查過程的一部分進行審查。這意味著像對待項目中的任何其他類型的測試或代碼一樣對待快照。
通過保持快照的重點、簡短并使用強制執(zhí)行這些風(fēng)格約定的工具來確保您的快照可讀。
如前所述,Jest 用于pretty-format使快照具有人類可讀性,但你可能會發(fā)現(xiàn)引入其他工具很有用,例如eslint-plugin-jest使用其no-large-snapshots選項或snapshot-diff組件快照比較功能,以促進提交簡短、重點突出的斷言。
目標是讓審查拉取請求中的快照變得容易,并與在測試套件失敗時重新生成快照的習(xí)慣作斗爭,而不是檢查其失敗的根本原因。
你的測試應(yīng)該是確定性的。在未更改的組件上多次運行相同的測試應(yīng)該每次都產(chǎn)生相同的結(jié)果。你有責(zé)任確保生成的快照不包含特定于平臺的數(shù)據(jù)或其他非確定性數(shù)據(jù)。
例如,如果你有一個使用的Clock組件?Date.now()
?,則每次運行測試用例時,從該組件生成的快照都會不同。在這種情況下,我們可以模擬 Date.now() 方法以在每次測試運行時返回一致的值:
Date.now = jest.fn(() => 1482363367071);
現(xiàn)在,每次快照測試用例運行時,?Date.now()
?都會?1482363367071
?一致地返回。無論何時運行測試,這都會導(dǎo)致為此組件生成相同的快照。
始終努力為快照使用描述性測試和/或快照名稱。最好的名稱描述了預(yù)期的快照內(nèi)容。這使得審閱者在審閱期間更容易驗證快照,并且任何人都可以在更新之前知道過時的快照是否是正確的行為。
例如,比較:
exports[`<UserName /> should handle some test case`] = `null`;
exports[`<UserName /> should handle some other test case`] = `
<div>
Alan Turing
</div>
`;
到:
exports[`<UserName /> should render null`] = `null`;
exports[`<UserName /> should render Alan Turing`] = `
<div>
Alan Turing
</div>
`;
由于后者準確地描述了輸出中的預(yù)期內(nèi)容,因此更清楚地看到什么時候出錯:
exports[`<UserName /> should render null`] = `
<div>
Alan Turing
</div>
`;
exports[`<UserName /> should render Alan Turing`] = `null`;
不,從 Jest 20 開始,當 Jest 在 CI 系統(tǒng)中運行時沒有明確傳遞?--updateSnapshot
?. 預(yù)計所有快照都是在 CI 上運行的代碼的一部分,并且由于新快照會自動通過,因此它們不應(yīng)通過在 CI 系統(tǒng)上運行的測試。建議始終提交所有快照并將它們保留在版本控制中。
是的,所有快照文件都應(yīng)該與它們所涵蓋的模塊及其測試一起提交。它們應(yīng)該被視為測試的一部分,類似于 Jest 中任何其他斷言的值。事實上,快照代表了源模塊在任何給定時間點的狀態(tài)。這樣,當修改源模塊時,Jest 可以分辨出與之前的版本相比發(fā)生了什么變化。它還可以在代碼審查期間提供許多額外的上下文,審查人員可以在其中更好地研究你的更改。
React和React Native組件是快照測試的一個很好的用例。但是,快照可以捕獲任何可序列化的值,并且應(yīng)該在目標是測試輸出是否正確的任何時候使用。Jest 存儲庫包含許多測試 Jest 本身輸出的示例、Jest 斷言庫的輸出以及來自 Jest 代碼庫各個部分的日志消息。請參閱Jest 存儲庫中對CLI 輸出進行快照的示例。
快照測試和視覺回歸測試是測試 UI 的兩種不同方式,它們用于不同的目的。視覺回歸測試工具獲取網(wǎng)頁的屏幕截圖并逐個像素地比較生成的圖像。使用 Snapshot 測試值被序列化,存儲在文本文件中,并使用 diff 算法進行比較。需要考慮不同的權(quán)衡,我們在Jest 博客中列出了構(gòu)建快照測試的原因。
快照測試只是 Jest 附帶的 20 多個斷言之一。快照測試的目的不是取代現(xiàn)有的單元測試,而是提供附加價值并使測試無痛。在某些情況下,快照測試可以潛在地消除對特定功能集(例如 React 組件)進行單元測試的需要,但它們也可以一起工作。
Jest 在重寫時考慮了性能,快照測試也不例外。由于快照存儲在文本文件中,因此這種測試方式既快速又可靠。Jest 為調(diào)用?toMatchSnapshot
?匹配器的每個測試文件生成一個新文件??煺盏拇笮》浅P。鹤鳛閰⒖迹琂est 代碼庫本身中所有快照文件的大小都小于 300 KB。
快照文件必須始終代表它們所覆蓋的模塊的當前狀態(tài)。因此,如果您正在合并兩個分支并在快照文件中遇到?jīng)_突,您可以手動解決沖突或通過運行 Jest 并檢查結(jié)果來更新快照文件。
雖然可以手動寫入快照文件,但這通常是不可行的??煺沼兄诖_定測試覆蓋的模塊的輸出是否已更改,而不是首先提供設(shè)計代碼的指導(dǎo)。
是的,以及任何其他測試。
更多建議: