解决 Jest 测试中遇到的 fetch 网络请求问题

阅读时长 9 分钟读完

在前端开发中,我们经常需要撰写单元测试来确保代码的质量和可靠性。Jest 是一个流行的 JavaScript 单元测试框架,它提供了很多强大的功能和灵活的 API 使得测试变得更加简单和高效。然而,在 Jest 中执行网络请求是一个常见的问题,特别是使用 fetch 请求的场景。在本文中,我们将探讨 Jest 中 fetch 网络请求的测试问题,并分享如何解决它们。

问题描述

在执行 Jest 测试时,单元测试通常会在 Node.js 环境下运行,而不是在浏览器中。这就意味着测试环境中没有浏览器提供的全局 fetch API。为了在测试中模拟 fetch 网络请求,我们通常会使用一些第三方的模块,例如 node-fetch、jest-fetch-mock 和 fetch-mock 等,这样我们就能够在测试中模拟 HTTP 请求并获得响应数据。但是,在使用这些模块时,我们会遇到一些常见的问题,例如模拟 fetch 请求无效,模拟 response 数据结构错误等等。

下面我们将通过一个简单的示例代码来说明这些问题:

这是一个通过 fetch 请求获取 JSON 数据的例子,我们现在需要对其进行单元测试。首先,安装 node-fetch 和 jest-fetch-mock 模块:

然后在测试用例中使用 jest-fetch-mock 来截获和模拟 fetch 请求和响应:

-- -------------------- ---- -------
-------------------
----- - -------- - - ----------------------
----- --------- - -----------------------

------------------- ---------- -- -- -
  ---------- ----- ---- ---- ----- ----- -- -- -
    ----- ---- - -- --- -- ----- ----- ---
    ----- -------- - --- -------------------------------
    ------------ - --------------------------------------

    ----- ------ - ----- -----------------------
    -----------------------------
  ---
---

根据我们的预期,测试应该成功执行并且 result 应该等于 data。但是,实际上我们会遇到一些问题,例如测试用例失败,模拟 fetch 请求无效,模拟 response 数据结构错误等。

解决方案

1. 使用 node-fetch instead of fetch-mock

第一种解决方案是使用 node-fetch 模块而非 jest-fetch-mock,这可以更好地模拟浏览器环境下的 fetch API。node-fetch 提供了可用于在 Node.js 环境中进行网络请求的 API,使用 node-fetch 的示例代码如下:

-- -------------------- ---- -------
--------------
----- ----- - ----------------------
----- --------- - ----- ----- -- -
  ----- --- - ----- -----------
  ----- ---- - ----- -----------
  ------ -----
--

-------------- - ----------

在测试用例中,我们不再需要 mockResolvedValue 方法,而是使用 node-fetch 模块去实际访问远程 API。示例代码如下:

-- -------------------- ---- -------
-------------------
----- --------- - -----------------------

------------------- ---------- -- -- -
  ---------- ----- ---- ---- ----- ----- -- -- -
    ----- ---- - -- --- -- ----- ----- ---
    ------------ - ---------- --
      -----------------
        ----- -- -- ----------------------
      --
    --

    ----- ------ - ----- -----------------------
    -----------------------------
  ---
---

这样的话,我们可以完美地在测试用例中执行网络请求,并根据我们的预期结果来断言结果。在使用 node-fetch 模块时,如果遇到代理、Cookie 或跨域等问题,可以使用 nock 模块来模拟和 mock。

2. 使用 fetch-mock 将 fetch mock 掉

第二种解决方案是使用 fetch-mock 模块来模拟 fetch 的响应。fetch-mock 是一个流行的模块,它提供了可以完全替代原生 fetch API 的 API,可以让我们更灵活地处理网络请求和响应。使用 fetch-mock 的示例代码如下:

在测试用例中,我们需要先使用 fetchMock.mock 方法将 fetch 函数 mock 掉并模拟响应,示例代码如下:

-- -------------------- ---- -------
-------------------
----- --------- - -----------------------
----- --------- - ----------------------

------------------- ---------- -- -- -
  ---------- ----- ---- ---- ----- ----- -- -- -
    ----- ---- - -- --- -- ----- ----- ---
    --------------------------- - ----- ---- ---

    ----- ------ - ----- -----------------------
    -----------------------------

    --------------------
  ---
---

这里我们使用 fetchMock.mock 方法将 '/api/data' 所有的 HTTP 请求 mock 掉,并返回一个响应对象,它的 body 属性等于我们预期的 data 数组。当然,在调用 fetchMock.mock 方法时,如果需要更多的配置选项,可以参考 fetch-mock 的官方文档。

3. 将 window.fetch 赋值给 global.fetch

第三种解决方案是在测试用例中将 window.fetch 赋值给 global.fetch,这样就可以在测试用例中使用原生的 fetch API 进行网络请求。示例代码如下:

在测试用例中,我们需要先将 window.fetch 赋值给 global.fetch,并在测试过程中使用原生的 fetch API 进行网络请求,示例代码如下:

-- -------------------- ---- -------
-------------------
----- --------- - -----------------------

------------------- ---------- -- -- -
  ---------- ----- ---- ---- ----- ----- -- -- -
    ----- ---- - -- --- -- ----- ----- ---
    ------------ - -------------
    ----- -------- - --- ------------------------------ -
      ------- ----
      -------- - --------------- ------------------ --
    ---

    ------------------ -------------------------------------

    ----- ------ - ----- -----------------------
    -----------------------------

    ---------------------------
  ---
---

这里我们使用 jest.spyOn 方法来监控 global.fetch 方法,并在测试用例中使用原生的 fetch API 来进行网络请求。当然,这种方案要求我们的测试用例运行在支持 fetch API 的浏览器中,可以在 jest-puppeteer 或 Jest 浏览器执行器中运行。这种方案对与项目中使用 window.fetch 而非 fetch 的情况来说是比较友好的。

总结

Jest 是一个强大的 JavaScript 单元测试框架,它提供了很多强大的功能和灵活的 API 使得测试变得更加简单和高效。然而,在 Jest 中执行网络请求是一个常见的问题,特别是使用 fetch 请求的场景。在本文中,我们讨论了 Jest 中 fetch 网络请求测试的若干问题,并提供了三种方案来解决这些问题。在实际的项目中,我们可以根据具体的情况选择相应的方案来测试网络请求,这样可以确保我们的单元测试更加完善和可靠。

关于本文的示例代码,它们也可以在我的 GitHub 仓库中找到:https://github.com/xxjwxc3/front_end_study/tree/main/Jest%20Fetch%20%E6%B5%8B%E8%AF%95

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64eecc23f6b2d6eab38c00b1

纠错
反馈