🧑💻测试 React Hooks 的完整指南 🗓 + Demo 🍿
文章目录
使用辅助方法优化测试
到目前为止,我们已经看到了如何完全测试我们的钩子。这种方法并不完美,但它有效。然而,我们能做得更好吗?
是的。请注意,我们为每次获取等待固定的 500 毫秒,但每个请求需要 200 到 500 毫秒。所以,我们显然是在浪费时间。我们可以通过等待每个请求花费的时间来更好地处理这个问题。
我们怎么做?一个简单的技术是执行断言,直到它通过或达到超时。让我们创建一个waitFor
执行此操作的函数。
async function waitFor(cb, timeout = 500) {
const step = 10;
let timeSpent = 0;
let timedOut = false;
while (true) {
try {
await sleep(step);
timeSpent += step;
cb();
break;
} catch {}
if (timeSpent >= timeout) {
timedOut = true;
break;
}
}
if (timedOut) {
throw new Error("timeout");
}
}
此函数只是try...catch
每 10 毫秒在块内运行一次回调 (cb) ,如果timeout
达到,则会引发错误。这允许我们运行断言,直到它以安全的方式通过(即没有无限循环)。
我们可以在我们的测试中使用它,如下所示:我们使用我们的waitFor
函数,而不是休眠 500 毫秒然后断言。
// INSTEAD OF
await act(() => sleep(500));
expect(container.textContent).toBe("url1");
// WE DO
await act(() =>
waitFor(() => {
expect(container.textContent).toBe("url1");
})
);
在所有此类断言中执行此操作,我们可以看到测试运行速度(代码)的显着差异。
现在,这一切都很棒,但也许我们不想通过 UI 测试钩子。也许我们想使用它的返回值来测试一个钩子。我们怎么做?
这并不难,因为我们已经可以访问钩子的返回值。它们就在组件内部。如果我们可以将这些变量放到全局范围内,它就会起作用。所以让我们这样做。
由于我们将通过其返回值而不是渲染 DOM 来测试我们的钩子,因此我们可以从组件中移除 HTML 渲染并使其渲染null
。我们还应该删除 hook 返回中的解构以使其更通用。因此,我们有了这个更新的测试组件。
// global variable
let result;
function TestComponent({ url }) {
result = useStaleRefresh(url, defaultValue);
return null;
}
现在钩子的返回值存储在result
一个全局变量中。我们可以查询它的断言。
// INSTEAD OF
expect(container.textContent).toContain("loading");
// WE DO
expect(result[1]).toBe(true);
// INSTEAD OF
expect(container.textContent).toBe("url1");
// WE DO
expect(result[0].data).toBe("url1");
在我们到处更改之后,我们可以看到我们的测试通过了(代码)。
至此,我们了解了测试 React Hooks 的要点。我们仍然可以进行一些改进,例如:
- 将
result
变量移动到局部作用域 - 无需为我们要测试的每个钩子创建一个组件
我们可以通过创建一个包含测试组件的工厂函数来实现。它还应该在测试组件中呈现钩子并让我们可以访问result
变量。让我们看看如何做到这一点。
首先,我们在函数内部移动TestComponent
和result
。我们还需要将 Hook 和 Hook 参数作为函数的参数传递,以便它们可以在我们的测试组件中使用。使用它,这就是我们所拥有的。我们正在调用这个函数renderHook
。
function renderHook(hook, args) {
let result = {};
function TestComponent({ hookArgs }) {
result.current = hook(...hookArgs);
return null;
}
act(() => {
render(<TestComponent hookArgs={args} />, container);
});
return result;
}
我们result
将数据存储在其中result.current
的原因是因为我们希望在测试运行时更新返回值。我们的钩子的返回值是一个数组,所以如果我们直接返回它,它就会被值复制。通过将它存储在一个对象中,我们返回对该对象的引用,以便可以通过更新来更新返回值result.current
。
现在,我们如何更新钩子?由于我们已经在使用闭包,让我们附上另一个rerender
可以做到这一点的函数。
最终的renderHook
函数如下所示:
function renderHook(hook, args) {
let result = {};
function TestComponent({ hookArgs }) {
result.current = hook(...hookArgs);
return null;
}
function rerender(args) {
act(() => {
render(<TestComponent hookArgs={args} />, container);
});
}
rerender(args);
return { result, rerender };
}
现在,我们可以在我们的测试中使用它。我们不使用act
and render
,而是执行以下操作:
const { rerender, result } = renderHook(useStaleRefresh, [
"url1",
defaultValue,
]);
然后,我们可以使用断言result.current
和更新钩子rerender
。这是一个简单的例子:
rerender(["url2", defaultValue]);
expect(result.current[1]).toBe(true); // check isLoading is true
在所有地方更改它后,您将看到它可以正常工作(代码)。
杰出的!现在我们有一个更清晰的抽象来测试钩子。我们仍然可以做得更好——例如,即使它没有改变,defaultValue
每次也需要传递给rerender
。我们可以解决这个问题。
但是我们不要太绕圈子,因为我们已经有了一个可以显着改善这种体验的库。
输入react-hooks-testing-library。
使用 React-hooks-testing-library 进行测试
React-hooks-testing-library 做了我们之前讨论过的所有事情,然后做了一些。例如,它处理容器安装和卸载,因此您不必在测试文件中执行此操作。这使我们可以专注于测试我们的钩子而不会分心。
它带有一个renderHook
返回rerender
和的函数result
。它还返回wait
,它类似于waitFor
,因此您不必自己实现它。
这是我们在 React-hooks-testing-library 中渲染钩子的方式。注意钩子是以回调的形式传递的。每次测试组件重新渲染时都会运行此回调。
const { result, wait, rerender } = renderHook(
({ url }) => useStaleRefresh(url, defaultValue),
{
initialProps: {
url: "url1",
},
}
);
然后,我们可以通过这样做来测试第一次渲染的结果是否isLoading
为真并返回值defaultValue
。与我们上面实现的完全相似。
expect(result.current[0]).toEqual(defaultValue);
expect(result.current[1]).toBe(true);
为了测试异步更新,我们可以使用返回的wait
方法renderHook
。它带有包裹,act()
所以我们不需要包裹act()
它。
await wait(() => {
expect(result.current[0].data).toEqual("url1");
});
expect(result.current[1]).toBe(false);
然后,我们可以使用rerender
新的 props 来更新它。注意我们不需要通过defaultValue
这里。
rerender({ url: "url2" });
最后,其余的测试将类似地进行(代码)。
包起来
我的目的是通过一个异步钩子的例子向你展示如何测试 React Hooks。我希望这可以帮助您自信地处理任何类型的钩子的测试,因为相同的方法应该适用于大多数钩子。
我建议您使用 React-hooks-testing-library,因为它已经完成,到目前为止我还没有遇到重大问题。如果您确实遇到问题,您现在知道如何使用本文中描述的测试钩子的复杂性来解决它。
- 洗漱包旅行套装 男出差商务洗簌袋便携化妆包女用品洗护大容量
- 蓝罐(Kjeldsens)曲奇饼干礼盒 454g 丹麦原装进口 休闲零食 节日送礼福利团购
- 适用于新款车载手机支架无线器快充智能自动感应汽车
- 皇顺适配名爵MG7汽车用品MG6PRO改装饰配件MG5门槛条ZS保护贴
温馨提示 : 非特殊注明,否则均为©李联华的博客网原创文章,本站文章未经授权禁止任何形式转载;IP地址:13.59.111.183,归属地:俄亥俄州Dublin ,欢迎您的访问!
文章链接:https://www.lilianhua.com/%f0%9f%8d%bf%f0%9f%a7%91%f0%9f%92%bb-complete-guide-to-test-react-hooks-%f0%9f%97%93-demo-%f0%9f%8d%bf.html
文章链接:https://www.lilianhua.com/%f0%9f%8d%bf%f0%9f%a7%91%f0%9f%92%bb-complete-guide-to-test-react-hooks-%f0%9f%97%93-demo-%f0%9f%8d%bf.html