React Hooks 是 React 16.8.0 中引入的新特性,它们允许开发者在不编写 class 组件的情况下使用 state 和其他 React 特性。虽然它们让代码变得更加简洁和易于阅读,但同时也给单元测试带来了一些新的挑战。在本文中,我们将探讨如何使用 Jest 测试 React 组件中使用 Hooks 的最佳实践。
基础 Hook 测试
让我们从使用最常见的 Hook - useState - 开始。假设我们有一个组件,它根据用户的输入更新文本:
-------- ----------- - ----- ------ -------- - ------------- -------- ------------------- - ---------------------------- - ------ - ------ ----------- ------------ ----------------------- -- -- -
我们可以编写简单的测试来检查它是否正常工作:
------ ----- ---- -------- ------ -------- ---------- ---- ------------------------- ------ --------- ---- -------------- --------------- ------- ---- -- -------- -- -- - ----- ----------- - ----------------- ---- ----- ----- - --------------------- ----------------------- - ------- - ------ ------- ------ - --- -------------------------------- -------- ---
此处我们使用了 @testing-library/react 库来帮助我们渲染 TextInput 组件。我们获取到组件渲染后返回的一个输入框元素对象 input,然后使用 fireEvent.change 模拟了用户的输入。最后我们使用 expect 断言来验证组件跟随用户输入的变化是否正确。
这种方式是在 hooks 的使用中最常见也是最基础的测试方式,只需简单的模拟用户操作即可,相信大家都已经非常熟悉了。
处理 useEffect 和 useState 联合测试的问题
当一个组件同时使用了 useEffect 和 useState 钩子时,测试可以变得更加棘手。让我们来看一个示例组件:
-------- --------- - ----- ------- --------- - ------------ ------------ -- - -------------- - ---- ------- -------- ------- -- --------- -------- ------------- - -------------- - --- - ------ - ----- ------ ------- ------- --------- ------- --------------------------- ----------- ------ -- -
这个组件有一个单独的状态 - count - 它通过点击按钮来增加。我们还添加了一个 useEffect 钩子,它根据 count 值的变化更新了浏览器的标题。
但是,在编写测试时,我们需要同时跟踪 count 和 useEffect 是否正常工作。我们可以通过下面的测试来确认回调函数是否被触发:
------ ----- ---- -------- ------ -------- ---------- ---- ------------------------- ------ ------- ---- ------------ ------------- ------- -------- ----- -- ------- -- -- - --------------- ---- ----- ------ - --------------------------------- ------------------------ -------------------------------- ------- - -------- ---
但是,这个测试并没有使用到 React 的状态。当我们试图仿效此用例使用其他 Hook 时会面临类似的挑战:我们如何知道 count 和 useEffect 是否按预期工作?
我们可以使用 React 的渲染函数 - act() - 来模拟组件内部的状态更新。act() 使我们能够对状态变更进行批量处理来增强渲染性能,也允许我们在更改状态后马上检索该状态的值。实际上,它就像是一个类似于 setTimeout 的 API,可以协调副作用的直观测试。我们可以使用 act() 来改写上面的测试用例,使其测试更准确:
------ ----- ---- -------- ------ -------- ---------- ---- ---- ------------------------- ------ ------- ---- ------------ ------------- ------- -------- ----- -- ------- -- -- - --- ------ --- --------- ----------------- --------------------------------- -- - ----- ----- - ------------------ ------- --------- - ------ ------ ------ --- --------------- ---- ----- ------ - --------------------------------- -------------------------------- ------- - -------- ------ -- - ------------------------ --- -------------------------------- ------- - -------- ---------------------- ------------------------------------------ ---
在这个版本的测试用例中,我们创建一个 count 变量 - 这是为了使之更容易访问 useState 中的内部 setCount 函数。我们使用 jest.spyOn 来 mock React 的 useState 方法,从而获取到 count 和 setCount 的实时状态。在渲染组件后,我们可以检查页面标题是否已正确更新。然后使用 act() 以函数的形式包装了我们的点击事件,并使用 fireEvent 对按钮进行了点击。最后,我们使用 expect 断言检测 count 的值,并验证 setCount 是否是一个函数。
在测试中 mock 网络请求
在单元测试中,我们希望避免向真实的 API 发送请求,而是用假数据来代替。为了实现这一目标,我们可以使用 Jest 的 mock 功能来 mock 网络请求。
让我们看一个组件,它从 API 获取 GitHub 用户信息并将其渲染到用户界面上:
------ ------ ---------- ---------- ---- -------- ------ ----- ---- -------- -------- ----------------------- - ----- ------ -------- - --------------- ------------ -- - ----- -------- --------------- - ----- -------- - ----- ------------------------------------------------------ ----------------------- - ---------------- -- ------------ -- ------- - ------ ---------------------- - ------ - ----- -------------------- ---- --------------------- ------------ -- ----------------- ------ -- - ------ ------- ------------
我们可以编写一个测试用例来验证这个组件是否能够正确地渲染出用户信息:
------ ----- ---- -------- ------ -------- --------------- ---- ------------------------- ------ ----- ---- -------- ------ ----------- ---- ---------------- ------------------- ----------------- ------- ---- ------ ----- -- -- - ----- -------- - - ----- - ----- ----- ----- ----------- ------------------------------------------------------- ---- --------- ---------- -- -- ------------------------------- -- --------------------------- ----- ----------- ------------- - ------------------- ------------------- ---- ----- ---- - ----- ----------------- -- --------------- ------- ----- ------ - ----------------------- ----- --- - ------------------- ----------- --------------------------------- ----------------------------------- -------------------------------- ---
在这个示例中,我们使用 Jest 的模拟功能来模拟 axios 的 get 请求,并将其返回的数据替换为我们自己的假数据。在渲染 UserProfile 组件后,我们使用传统的等待方式 - waitForElement - 来等待用户数据呈现。最后,我们可以断言我们的字符串是否在页面上显示。
总结
React Hooks 带来了更加简洁和可读的 React 代码。然而,使用 Hook 后产生的测试问题是实现这个目标的一部分。幸运的是,我们可以通过仔细考虑单元测试的用例和 React 测试 API - 如 act() - 来解决这些问题,并且使用 Jest 的 mock 功能可以使测试更加容易和高效。相信这篇文章可以帮助大家理解并运用好 Jest 测试 React Hooks。
参考链接
来源:JavaScript中文网 ,转载请联系管理员! 本文地址:https://www.javascriptcn.com/post/64735424968c7c53b00cac94