使用 Jest 測試 React 應用程序的實用指南

已發表: 2022-03-10
快速總結↬構建一個運行良好的應用程序需要良好的測試; 否則,知道您的應用程序是否按預期工作將是一個猜測和運氣的問題。 Jest 是可用於測試 React 應用程序的最佳工具之一。 在本文中,您將了解為您的 React 組件和應用程序創建可靠測試所需的一切。

在本文中,我將向您介紹一個名為 Jest 的 React 測試工具,以及用於測試 React 組件的流行庫 Enzyme。 我將向您介紹 Jest 測試技術,包括:運行測試、測試 React 組件、快照測試和模擬。 如果您是測試新手並且想知道如何開始,您會發現本教程很有幫助,因為我們將從測試介紹開始。 最後,您將啟動並運行,使用 Jest 和 Enzyme 測試 React 應用程序。 您應該熟悉 React 才能學習本教程。

測試簡介

測試是對代碼如何執行的逐行審查。 應用程序的一套測試包括各種代碼,以驗證應用程序是否成功執行且沒有錯誤。 當對代碼進行更新時,測試也會派上用場。 更新一段代碼後,您可以運行測試以確保更新不會破壞應用程序中已有的功能。

為什麼要測試?

在做某事之前了解我們為什麼要做某事是很好的。 那麼,為什麼要測試,它的目的是什麼?

  1. 測試的第一個目的是防止回歸。 回歸是先前已修復的錯誤再次出現。 它使某個功能在某個事件發生後停止按預期運行。
  2. 測試確保複雜組件和模塊化應用程序的功能。
  3. 軟件應用程序或產品的有效性能需要進行測試。

測試使應用程序更健壯,更不容易出錯。 這是一種驗證您的代碼是否按照您希望的方式運行以及您的應用程序是否按預期為您的用戶工作的方法。

跳躍後更多! 繼續往下看↓

讓我們回顧一下測試的類型以及它們的作用。

單元測試

在這種類型的測試中,測試軟件的各個單元或組件。 一個單元可能是一個單獨的函數、方法、過程、模塊或對象。 單元測試隔離一段代碼並驗證其正確性,以驗證軟件代碼的每個單元是否按預期執行。

在單元測試中,對各個程序或功能進行測試以保證它們正常運行,並且對所有組件進行單獨測試。 例如,測試函數或程序中的語句或循環是否正常運行將屬於單元測試的範圍。

組件測試

組件測試驗證應用程序各個部分的功能。 獨立於其他組件對每個組件執行測試。 通常,React 應用程序由幾個組件組成,因此組件測試處理單獨測試這些組件。

例如,考慮一個網站,該網站具有包含許多組件的不同網頁。 每個組件都有自己的子組件。 在不考慮與其他組件集成的情況下測試每個模塊稱為組件測試。

在 React 中進行這樣的測試需要更複雜的工具。 因此,我們需要 Jest,有時還需要更複雜的工具,例如 Enzyme,稍後我們將簡要討論。

快照測試

快照測試可確保 Web 應用程序的用戶界面 (UI) 不會意外更改。 它及時捕獲組件的代碼,以便我們可以將處於一種狀態的組件與它可能採用的任何其他可能狀態進行比較。

我們將在後面的部分了解快照測試。

測試的優缺點

測試很棒,應該做,但它有優點也有缺點。

優點

  1. 它可以防止意外的回歸。
  2. 它允許開發人員專注於當前的任務,而不是擔心過去。
  3. 它允許模塊化構建應用程序,否則該應用程序將過於復雜而無法構建。
  4. 它減少了手動驗證的需要。

缺點

  1. 您需要編寫更多代碼,以及調試和維護。
  2. 非關鍵測試失敗可能會導致應用程序在持續集成方面被拒絕。

玩笑簡介

Jest 是一個令人愉快的 JavaScript 測試框架,專注於簡單性。 它可以使用 npm 或 Yarn 安裝。 Jest 適合更廣泛的實用程序類別,稱為測試運行程序。 它適用於 React 應用程序,但它也適用於 React 應用程序之外。

Enzyme 是一個用於測試 React 應用程序的庫。 它旨在測試組件,並且可以編寫模擬操作以確認 UI 是否正常工作的斷言。

Jest 和 Enzyme 相得益彰,因此在本文中我們將同時使用兩者。

用 Jest 運行測試的過程

在本節中,我們將安裝 Jest 並編寫測試。 如果您是 React 新手,那麼我建議您使用 Create React App,因為它已準備好使用並隨 Jest 一起提供。

 npm init react-app my-app

我們需要用react-test-renderer安裝 Enzyme **** 和enzyme-adapter-react-16 (數量應該基於你使用的 React 版本)。

 npm install --save-dev enzyme enzyme-adapter-react-16 react-test-renderer

現在我們已經用 Jest 和 Enzyme 創建了我們的項目,我們需要在項目的src文件夾中創建一個setupTest.js文件。 該文件應如下所示:

 import { configure } from "enzyme"; import Adapter from "enzyme-adapter-react-16"; configure({ adapter: new Adapter() });

這會導入 Enzyme 並設置適配器來運行我們的測試。

在繼續之前,讓我們學習一些基礎知識。 本文中使用了很多關鍵的東西,您需要了解它們。

  • ittest你可以將一個函數傳遞給這個方法,然後測試運行器會將該函數作為一個測試塊來執行。
  • describe此可選方法用於對任意數量的ittest語句進行分組。
  • expect這是測試需要通過的條件。 它將接收到的參數與匹配器進行比較。 它還使您可以訪問許多匹配器,這些匹配器可以讓您驗證不同的事物。 您可以在文檔中閱讀有關它的更多信息。
  • mount這個方法渲染整個 DOM,包括父組件的子組件,我們在其中運行測試。
  • shallow這僅呈現我們正在測試的單個組件。 它不渲染子組件。 這使我們能夠單獨測試組件。

創建測試文件

Jest 如何知道什麼是測試文件,什麼不是? 第一條規則是在任何目錄中找到的名為__test__的任何文件都被視為測試。 如果您將 JavaScript 文件放在其中一個文件夾中,無論好壞,Jest 都會在您調用 Jest 時嘗試運行它。 第二條規則是 Jest 將識別任何帶有.spec.js.test.js後綴的文件。 它將搜索整個存儲庫中所有文件夾和所有文件的名稱。

讓我們為為本教程創建的 React 迷你應用程序創建我們的第一個測試。 你可以在 GitHub 上克隆它。 運行npm install安裝所有包,然後npm start啟動應用程序。 檢查README.md文件以獲取更多信息。

讓我們打開App.test.js來編寫我們的第一個測試。 首先,檢查我們的應用組件是否正確渲染以及我們是否指定了輸出:

 it("renders without crashing", () => { shallow(<App />); }); it("renders Account header", () => { const wrapper = shallow(<App />); const welcome = <h1>Display Active Users Account Details</h1>; expect(wrapper.contains(welcome)).toEqual(true); });

在上面的測試中,第一個測試使用shallow ,檢查我們的應用組件是否正確呈現而不會崩潰。 請記住, shallow方法僅呈現單個組件,沒有子組件。

第二個測試檢查我們是否在我們的應用程序組件中指定了“顯示活動用戶帳戶”的h1標記輸出,並帶有toEqual的 Jest 匹配器。

現在,運行測試:

 npm run test /* OR */ npm test

終端中的輸出應如下所示:

 PASS src/App.test.js √ renders without crashing (34ms) √ renders Account header (13ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 11.239s, estimated 16s Ran all test suites related to changed files. Watch Usage: Press w to show more.

如您所見,我們的測試通過了。 它表明我們有一個名為App.test.js的測試套件,當 Jest 運行時有兩個成功的測試。 稍後我們將討論快照測試,您還將看到一個失敗的測試示例。

跳過或隔離測試

跳過或隔離測試意味著當 Jest 運行時,不會運行特定的標記測試。

 it.skip("renders without crashing", () => { shallow(<App />); }); it("renders Account header", () => { const wrapper = shallow(<App />); const header = <h1>Display Active Users Account Details</h1>; expect(wrapper.contains(header)).toEqual(true); });

我們的第一個測試將被跳過,因為我們使用了skip方法來隔離測試。 因此,當 Jest 運行時,它不會運行或對我們的測試進行任何更改。 只有第二個會運行。 您也可以使用it.only()

對測試文件進行更改然後不得不再次手動運行npm test有點令人沮喪。 Jest 有一個很好的功能,稱為監視模式,它監視文件更改並相應地運行測試。 要在監視模式下運行 Jest,您可以運行npm test -- --watchjest --watch 。 在本教程的其餘部分,我還建議讓 Jest 在終端窗口中運行。

模擬功能

模擬是對像或模塊的令人信服的副本,沒有任何真正的內部運作。 它可能有一點點功能,但與真實的東西相比,它是一個模擬。 它可以由 Jest 自動創建或手動創建。

我們為什麼要嘲諷? 模擬減少了依賴項的數量——即在運行測試時必須加載和解析的相關文件的數量。 因此,使用大量模擬可以使測試執行得更快。

模擬函數也稱為“間諜”,因為它們讓您可以監視由其他代碼直接調用的函數的行為,而不僅僅是測試輸出。

有兩種方法可以模擬一個函數:或者通過創建一個模擬函數來在測試代碼中使用它,或者通過編寫一個手動模擬來覆蓋模塊依賴項。

手動模擬 **** 用於使用模擬數據存根功能。 例如,您可能希望創建一個允許您使用假數據的手動模擬,而不是訪問遠程資源(如網站或數據庫)。

我們將在下一節中使用模擬函數。

測試 React 組件

本節將結合我們迄今為止在理解如何測試 React 組件方面獲得的所有知識。 測試涉及確保組件的輸出沒有意外更改為其他內容。 以正確的方式構建組件是迄今為止確保成功測試的最有效方法。

我們可以做的一件事是測試組件的 props — 具體來說,測試一個組件的 props 是否正在傳遞給另一個組件。 Jest 和 Enzyme API 允許我們創建一個模擬函數來模擬 props 是否在組件之間傳遞。

我們必須將用戶帳戶道具從主App組件傳遞到Account組件。 我們需要將用戶帳戶詳細信息提供給Account以呈現用戶的活動帳戶。 這就是模擬派上用場的地方,使我們能夠使用假數據測試我們的組件。

讓我們為user道具創建一個模擬:

 const user = { name: "Adeneye David", email: "[email protected]", username: "Dave", };

我們在我們的測試文件中創建了一個手動模擬函數並將其包裝在組件周圍。 假設我們正在測試一個大型用戶數據庫。 不建議直接從我們的測試文件訪問數據庫。 相反,我們創建了一個模擬函數,它使我們能夠使用假數據來測試我們的組件。

 describe(" ", () => { it("accepts user account props", () => { const wrapper = mount(<Account user={user} />); expect(wrapper.props().user).toEqual(user); }); it("contains users account email", () => { const wrapper = mount(<Account user={user} />); const value = wrapper.find("p").text(); expect(value).toEqual("[email protected]"); }); }); describe(" ", () => { it("accepts user account props", () => { const wrapper = mount(<Account user={user} />); expect(wrapper.props().user).toEqual(user); }); it("contains users account email", () => { const wrapper = mount(<Account user={user} />); const value = wrapper.find("p").text(); expect(value).toEqual("[email protected]"); }); });

我們上面有兩個測試,我們使用了一個describe層,它接受被測試的組件。 通過指定我們期望通過測試通過的道具和值,我們可以繼續。

在第一個測試中,我們檢查傳遞給掛載組件的 props 是否等於我們在上面創建的模擬 props。

對於第二個測試,我們將 user 屬性傳遞給掛載的Account組件。 然後,我們檢查是否可以找到與Account組件中的內容相對應的<p>元素。 當我們運行測試套件時,您會看到測試運行成功。

我們還可以測試組件的狀態。 讓我們檢查錯誤消息的狀態是否等於 null:

 it("renders correctly with no error message", () => { const wrapper = mount( ); expect(wrapper.state("error")).toEqual(null); }); it("renders correctly with no error message", () => { const wrapper = mount( ); expect(wrapper.state("error")).toEqual(null); });

在此測試中,我們使用toEqual()匹配器檢查組件錯誤的狀態是否等於 null。 如果我們的應用程序中有錯誤消息,則測試將在運行時失敗。

在下一節中,我們將介紹如何使用快照測試來測試 React 組件,這是另一種驚人的技術。

快照測試

快照測試在某個時刻捕獲組件的代碼,以便將其與存儲在測試旁邊的參考快照文件進行比較。 它用於跟踪應用程序 UI 的變化。

快照的實際代碼表示是一個 JSON 文件,並且該 JSON 包含創建快照時組件外觀的記錄。 在測試期間,Jest 將此 JSON 文件的內容與測試期間組件的輸出進行比較。 如果它們匹配,則測試通過; 如果他們不這樣做,則測試失敗。

要將 Enzyme 包裝器轉換為與 Jest 快照測試兼容的格式,我們必須安裝enzyme-to-json

 npm install --save-dev enzyme-to-json

讓我們創建我們的快照測試。 當我們第一次運行它時,該組件代碼的快照將被組合併保存在src目錄中的一個新的__snapshots__文件夾中。

 it("renders correctly", () => { const tree = shallow(<App />); expect(toJson(tree)).toMatchSnapshot(); });

當上面的測試成功運行時,當前的 UI 組件將與現有的進行比較。

現在,讓我們運行測試:

 npm run test

當測試套件運行時,將生成一個新的快照並將其保存到__snapshots__文件夾中。 當我們隨後運行測試時,Jest 會檢查組件是否與快照匹配。

如上一節所述,Enzyme 包中的shallow方法用於渲染單個組件,僅此而已。 它不渲染子組件。 相反,它為我們提供了一種很好的方式來隔離代碼並在調試時獲得更好的信息。 另一種名為mount的方法用於渲染完整的 DOM,包括我們正在運行測試的父組件的子組件。

我們還可以更新我們的快照,讓我們對我們的組件進行一些更改以使我們的測試失敗,這會發生,因為該組件不再對應於我們在快照文件中的內容。 為此,讓我們將組件中的<h3>標籤從<h3> Loading...</h3>更改為<h3>Fetching Users...</h3> 。 當測試運行時,我們將在終端中得到以下內容:

 FAIL src/App.test.js (30.696s) × renders correctly (44ms) ● renders correctly expect(received).toMatchSnapshot() Snapshot name: `renders correctly 1 - Snapshot + Received FAIL src/App.test.js (30.696s) × renders correctly (44ms) ● renders correctly expect(received).toMatchSnapshot() Snapshot name: `renders correctly 1 - Snapshot + Received

顯示活動用戶帳戶詳細信息

- 加載中... + 獲取用戶...

7 | it("正確渲染", () => { 8 | 常量包裝器 = 淺( ); > 9 | 期望(toJson(包裝器)).toMatchSnapshot(); | ^ 10 | }); 11 | 12 | /* it("渲染不會崩潰", () => { 在對象。 (src/App.test.js:9:27) › 1 個快照失敗。 快照摘要 › 1 個測試套件的 1 個快照失敗。 檢查您的代碼更改或按 `u` 更新它們。 測試套件:1 個失敗,總共 1 個 測試:1 次失敗,總共 1 次 快照:1 個失敗,共 1 個 時間:92.274s 運行與更改的文件相關的所有測試套件。 觀看用法:按 w 顯示更多。

如果我們希望我們的測試通過,我們要么將測試更改為之前的狀態,要么更新快照文件。 在命令行中,Jest 提供有關如何更新快照的說明。 首先,在命令行中按w顯示更多內容,然後按u更新快照。

 › Press u to update failing snapshots.

當我們按u更新快照時,測試將通過。

結論

我希望您喜歡本教程。 我們已經使用 Enzyme 測試庫學習了一些 Jest 測試技術。 我還向您介紹了運行測試、測試 React 組件、模擬和快照測試的過程。 如果您有任何問題,可以將它們留在下面的評論部分,我很樂意回答每個問題並與您一起解決任何問題。

資源和進一步閱讀

  • 笑話文檔
  • 酶文檔
  • “如何測試 React 組件:完整指南”,Mohammad Iqbal,freeCodeCamp
  • “用 Jest 和 Enzyme 測試反應”,Dominic Fraser,CodeClan