使用 Jest 覆盖各个测试中的函数

使用 jest 覆盖各个测试中的函数

有时您想在某些测试中模拟某个函数,但不想在其他测试中模拟。有时您想为不同的测试提供不同的模拟。 jest 使这变得棘手:它的默认行为是覆盖整个测试文件的包函数,而不仅仅是单个测试。如果您使用过 python 的 @patch 或 laravel 的服务容器等灵活工具,这似乎很奇怪。

这篇文章将向您展示如何模拟单个测试的函数,然后在未提供模拟的情况下回退到原始实现。将给出 commonjs 和 es 模块的示例。本文中演示的技术适用于第一方模块和第三方包。

commonjs 与 es 模块

由于我们将在这篇文章中介绍多个模块系统,因此了解它们是什么很重要。

commonjs(简称cjs)是node.js中的模块系统。它使用 module.exports 导出函数并使用 require() 导入函数:

// commonjs export function greet() {  return "hello, world!";}module.exports = { greet };

登录后复制

// commonjs importconst getuserslist = require('./greet');

登录后复制

es 模块(缩写为 esm)是浏览器使用的模块系统。它使用export关键字导出函数并使用import关键字导入函数:

// es module exportexport default function greet() {  return "hello, world!";}

登录后复制

// es module importimport { greet } from "./greet";

登录后复制

在撰写本文时,大多数前端 javascript 开发人员都使用 es 模块,许多服务器端 js 开发人员也使用它们。然而,commonjs 仍然是 node 的默认设置。无论您使用哪个系统,都值得阅读整篇文章来了解 jest 的模拟系统。

使用 commonjs 模拟单个导出函数

通常,commonjs 文件将使用对象语法导出其模块,如下所示:

// commonjs export function greet() {  return "hello, world!";}module.exports = { greet: greet };

登录后复制

但是,也可以自行导出函数:

// commonjs export function greet() {  return "hello, world!";}module.exports = greet;

登录后复制

我不一定建议在您自己的代码中执行此操作:导出对象会让您在开发应用程序时减少一些麻烦。然而,这种情况很常见,值得讨论如何在 commonjs 中模拟裸导出的函数,然后在测试未提供自己的实现时回退到原始函数。

假设我们有以下 commonjs 文件,我们想在测试期间模拟:

// cjsfunction.jsfunction testfunc() {  return "original";}module.exports = testfunc;

登录后复制

我们可以使用以下代码在测试中模拟它:

const testfunc = require("./cjsfunction");jest.mock("./cjsfunction");beforeeach(() => {  testfunc.mockimplementation(jest.requireactual("./cjsfunction"));});it("can override the implementation for a single test", () => {  testfunc.mockimplementation(() => "mock implementation");  expect(testfunc()).tobe("mock implementation");  expect(testfunc.mock.calls).tohavelength(1);});it("can override the return value for a single test", () => {  testfunc.mockreturnvalue("mock return value");  expect(testfunc()).tobe("mock return value");  expect(testfunc.mock.calls).tohavelength(1);});it("returns the original implementation when no overrides exist", () => {  expect(testfunc()).tobe("original");  expect(testfunc.mock.calls).tohavelength(1);});

登录后复制

怎么运行的

当我们调用 jest.mock(“./cjsfunction”) 时,这会用自动模拟(文档)替换模块(文件及其所有导出)。当调用自动模拟时,它将返回未定义。但是,它将提供用于覆盖模拟的实现、返回值等的方法。你可以在 jest mock functions 文档中看到它提供的所有属性和方法。

我们可以使用mock的mockimplementation()方法自动将mock的实现设置为原始模块的实现。 jest 提供了一个 jest.requireactual() 方法,该方法将始终加载原始模块,即使它当前正在被模拟。

mock 实现和返回值在每次测试后都会自动清除,因此我们可以将回调函数传递给 jest 的 beforeeach() 函数,该函数在每次测试前将模拟的实现设置为原始实现。然后,任何希望提供自己的返回值或实现的测试都可以在测试主体中手动执行此操作。

导出对象时模拟 commonjs

假设上面的代码导出了一个对象而不是单个函数:

// cjsmodule.jsfunction testfunc() {  return "original";}module.exports = {  testfunc: testfunc,};

登录后复制

我们的测试将如下所示:

const cjsmodule = require("./cjsmodule");aftereach(() => {  jest.restoreallmocks();});it("can override the implementation for a single test", () => {  jest    .spyon(cjsmodule, "testfunc")    .mockimplementation(() => "mock implementation");  expect(cjsmodule.testfunc()).tobe("mock implementation");  expect(cjsmodule.testfunc.mock.calls).tohavelength(1);});it("can override the return value for a single test", () => {  jest.spyon(cjsmodule, "testfunc").mockreturnvalue("mock return value");  expect(cjsmodule.testfunc()).tobe("mock return value");  expect(cjsmodule.testfunc.mock.calls).tohavelength(1);});it("returns the original implementation when no overrides exist", () => {  expect(cjsmodule.testfunc()).tobe("original");});it("can spy on calls while keeping the original implementation", () => {  jest.spyon(cjsmodule, "testfunc");  expect(cjsmodule.testfunc()).tobe("original");  expect(cjsmodule.testfunc.mock.calls).tohavelength(1);});

登录后复制

怎么运行的

jest.spyon() 方法允许 jest 记录对对象方法的调用并提供自己的替换。这适用于对象,我们可以使用它,因为我们的模块正在导出包含我们的函数的对象。

spyon() 方法是一个模拟方法,因此必须重置其状态。 jest spyon() 文档建议在 aftereach() 回调中使用 jest.restoreallmocks() 重置状态,这就是我们上面所做的。如果我们不这样做,则在调用spyon()后,模拟将在下一次测试中返回未定义。

模拟es模块

es 模块可以有默认的和命名的导出:

// esmmodule.jsexport default function () {  return "original default";}export function named() {  return "original named";}

登录后复制

上面文件的测试如下所示:

import * as esmmodule from "./esmmodule";aftereach(() => {  jest.restoreallmocks();});it("can override the implementation for a single test", () => {  jest    .spyon(esmmodule, "default")    .mockimplementation(() => "mock implementation default");  jest    .spyon(esmmodule, "named")    .mockimplementation(() => "mock implementation named");  expect(esmmodule.default()).tobe("mock implementation default");  expect(esmmodule.named()).tobe("mock implementation named");  expect(esmmodule.default.mock.calls).tohavelength(1);  expect(esmmodule.named.mock.calls).tohavelength(1);});it("can override the return value for a single test", () => {  jest.spyon(esmmodule, "default").mockreturnvalue("mock return value default");  jest.spyon(esmmodule, "named").mockreturnvalue("mock return value named");  expect(esmmodule.default()).tobe("mock return value default");  expect(esmmodule.named()).tobe("mock return value named");  expect(esmmodule.default.mock.calls).tohavelength(1);  expect(esmmodule.named.mock.calls).tohavelength(1);});it("returns the original implementation when no overrides exist", () => {  expect(esmmodule.default()).tobe("original default");  expect(esmmodule.named()).tobe("original named");});

登录后复制

怎么运行的

这看起来几乎与前面的 commonjs 示例相同,但有几个关键区别。

首先,我们将模块作为命名空间导入。

import * as esmmodule from "./esmmodule";

登录后复制

然后当我们想要监视默认导出时,我们使用“default”:

  jest    .spyon(esmmodule, "default")    .mockimplementation(() => "mock implementation default");

登录后复制

es 模块导入故障排除

有时尝试使用第三方包调用 jest.spyon() 时,你会收到如下错误:

    typeerror: cannot redefine property: usenavigate        at function.defineproperty ()

登录后复制

当您遇到此错误时,您需要模拟导致问题的包:

import * as reactrouterdom from "react-router-dom";// add this:jest.mock("react-router-dom", () => {  const originalmodule = jest.requireactual("react-router-dom");  return {    __esmodule: true,    ...originalmodule,  };});aftereach(() => {  jest.restoreallmocks();});

登录后复制

此代码将模块替换为 jest es 模块模拟,其中包含使用 jest.mocks 的工厂参数的模块的所有原始属性。每当在 jest.mock 中使用工厂参数来模拟 es 模块时,都需要 __esmodule 属性(文档)。

如果需要,您还可以替换工厂参数中的单个函数。例如,如果消费者在 router 上下文之外调用 usenavigate(),react router 将抛出错误,因此如果需要,我们可以使用 jest.mock() 在整个测试文件中替换该函数:

jest.mock("react-router-dom", () => {  const originalModule = jest.requireActual("react-router-dom");  return {    __esModule: true,    ...originalModule,    // Dummy that does nothing.    useNavigate() {      return function navigate(_location) {        return;      };    },  };});

登录后复制

包起来

我希望这些信息在您编写自己的测试时很有价值。当测试本身未提供实现时,并非每个应用程序都会受益于能够回退到默认实现。事实上,许多应用程序希望对整个测试文件使用相同的模拟。然而,这篇文章中展示的技术将使您能够对模拟进行细粒度的控制。

如果我遗漏了某些内容,或者是否有我没有包含在这篇文章中的内容,请告诉我。

以上就是使用 Jest 覆盖各个测试中的函数的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2672121.html

(0)
上一篇 2025年3月7日 13:20:51
下一篇 2025年3月7日 13:21:05

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • Devto 系列:如何开始编写代码

    选择一种编程语言并学习 决定编程语言非常重要,特别是当您是初学者时。 话虽如此,学习任何东西的关键就是开始。这可能看起来很困难。有一些最受欢迎且适合初学者的选项可供考虑。不过,C、C++、Java 和 Python 是最流行的高级编程语言。…

    2025年3月7日
    200
  • 如何将shadcn添加到现有项目中

    如果您是一名 web 开发人员,您很可能听说过 shadcn/ui,它是基于 radix ui 的最流行的组件库之一。在这篇文章中,我们将探讨如何将 shadcn 添加到现有项目中。 根据您的项目设置方式以及您使用的框架,将 shadcn …

    2025年3月7日
    200
  • ShowDEV – 我们为您的产品构建了一体化的人工智能指挥中心

    嘿,开发者们! ? 您正在构建人工智能驱动的应用程序吗?是否在管理多个人工智能提供商、优化成本和跟踪提示方面遇到困难?今天我们有一些令人兴奋的事情要与您分享! 我的兄弟@vaibhavacharya(人工智能向导)和我在过去几年一直致力于各…

    2025年3月7日
    200
  • 在 JavaScript 中使用 Pieces SDK Copilot 包装器

    在参加全球黑客周时,我注意到其中一个挑战(使用 pieces 的 hello world 挑战)没有演练。所以我决定为这个挑战做一个简单的“操作方法”。 在本文中,我们将使用 typescript sdk 向 pieces 询问这个问题: …

    2025年3月7日
    200
  • 使用 Laravel + React 安装 Shadcn/ui❤️

    目前有很多css框架,例如bootstrap、bulma、semantic ui等。这可以加快构建显示(用户界面)的速度。目前流行的 css 工具之一是 shadcn/ui,它之前是什么? 在其官方网站shadcn/ui上表示 “我们可以复…

    2025年3月7日 编程技术
    200
  • 使用 Laravel 和 jQuery 实现无限滚动

    与传统分页相比,无限滚动提供了一种更现代、更流畅的数据加载方式。当用户向下滚动页面时,新数据会自动加载,而不是单击分页链接。 先决条件 laravel 和 jquery 的基础知识。具有分页模型的 laravel 项目(例如,用户)。 第 …

    2025年3月7日
    200
  • 在 JavaScript 中使用最小和最大堆管理流数据:数字运动员健康技术视角

    数据管理在健康技术中至关重要。无论是跟踪运动员的表现指标还是监控运动员的恢复时间,有效地组织数据都可以对洞察的获取方式产生重大影响。在这种情况下管理数据的一种强大工具是堆,特别是最小堆和最大堆。在这篇文章中,我们将使用与运动员数据管理相关的…

    2025年3月7日
    200
  • 最佳黑客马拉松项目️

    嘿那里!? …这是 2024 年最好的基于网络的黑客马拉松项目,它们可能会专注于尖端技术并解决现实世界的问题。以下是一些可以在黑客马拉松中脱颖而出的想法: ** AI 驱动的辅助工具**描述:一款使用 AI 来增强残障人士无障碍…

    2025年3月7日
    200
  • 揭秘合并排序:分治排序初学者指南

    归并排序由约翰·冯·诺依曼于 1945 年提出,主要是为了提高大型数据集的排序效率。冯·诺依曼的算法旨在使用分而治之的方法提供一致且可预测的排序过程。这种策略允许归并排序有效地处理小型和大型数据集,保证在所有情况下都能实现稳定的排序,时间复…

    2025年3月7日
    200
  • 处理问题

    我制作了explainer.js,一个用于处理文件并输出代码块和解释的 CLI 工具。如果您不知道文件中发生了什么,那么这可能会有所帮助。使用 Commander.js 和 Groq SDK 构建!看看@ https://github.co…

    2025年3月7日
    200

发表回复

登录后才能评论