jest 是如何 mock 掉模块的

二向箔安全员
• 阅读 7806

jest 里有两种 mock,一种是方法的 mock,还有一种是模块的 mock。这里我们来看一下模块的 mock 是如何实现的。

比如我们要 mock 掉 node 内置的 fs 模块,我们只要这么写:

const fs = require('fs');

jest.mock('fs');

console.log(fs.statSync('/tmp/file')); // undefined

jest 在执行这个文件的时候,首先会对代码进行转换,转换分成两步。

第一步是提升 jest.mock('fs'),让它能作用在 require 之前,转换后的代码如下:

jest.mock('fs');

const fs = require('fs');

jest.mock('fs');

console.log(fs.statSync('/tmp/file'));

第二部是包一层匿名方法,这一步跟 node 的模块实现类似:

(function(module, exports, require, __dirname, __filename, global, jest){
  jest.mock('fs');

  const fs = require('fs');

  console.log(fs.statSync('/tmp/file'));
}))

代码转换完后,jest 需要注入自己的 require 实现,这个一步通过让转换后的代码在 vm 模块创建的新的上下文里执行,最终生成一个可以执行的匿名方法实现。

const vm = require('vm');

const code = '转换后的代码';

const script = new vm.Script(code);

const result = script.runInContext(context); // describe, it 等全局方法在这里注入

result.call(
  module,
  exports,
  require, // jest 自己的 require 实现,
  ...
);

最后,我们用伪代码来描述下 require 的实现:

const shouldMock = {};

function mock(moduleName) {
  // jest 会给每个模块生成一个 moduleId, 比如这里是 `node:fs:` 表示这是一个 node 模块
  const moduleId = getModuleId(moduleName);
  shouldMock[moduleId] = true;
}

// 这个就是 jest 给我们的代码注入的 require 方法
function requireModuleOrMock(moduleName) {
  if(shouldMock(moduleName)) {
    return requireMockModule(moduleName);
  } else {
    return requireModule(moduleName);
  }
}

function shouldMock(moduleName) {
  const moduleId = getModuleId(moduleName);
  return moduleId in shouldMock;
}

function requireMockModule(moduleName) {
  const moduleExports =  requireModule(moduleName);
  return Object.keys(moduleExports).reduce((mock, key) => {
    mock[key] = () => {}; // mock 的方法
    return mock;
  }, {})
}

function requireModule(moduleName) {
  return require(moduleName); // 这个是原始的 require
}
点赞
收藏
评论区
推荐文章
基于SpringBoot实现单元测试的多种情境/方法(二)
本文分享自天翼云开发者社区@《》,作者:才开始学技术的小白1Mock基础回顾在上一篇分享中我们详细介绍了简单的、用mock来模拟接口测试环境的方法,具体的使用样例我们再回顾一下:1.首先是最简单的不需要传参的示例,需要注意的是,可能@Resource这个注
liam liam
2年前
Mock 语法讲解
是生成随机数据,拦截Ajax请求的JavaScript库。本文来介绍下Mock的常用语法。模拟数据生成随机数据Mock.Random.boolean()生成一个随机的布尔值。例如:返回值为true或false。Mock.Random.integer(min
一文教会你mock(Mockito和PowerMock双剑合璧)
Mock有模仿、伪造的含义。Mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。
马丁路德 马丁路德
4年前
好家伙,这些写 CSS 的新姿势你还不知道?
现在大部分搞前端的应该还是这样写CSS的:.mock {    margin: auto;    fontsize: 16px;    // ...}<div class'mock'mock</div以上代码就是举个例子,大部分情况应该都是写一个类,然后整一堆样式进去。但是这种方式写多了以后,你应该
liam liam
1年前
利用 Apifox 的 Mock 功能快速构建业务数据模拟场景
Apifox拥有强大的功能,兼容Mock.js语法的同时还提供Nunjucks和自定义脚本支持,能够满足不同场景需求。今天给大家分享一些常见业务场景的Mock使用技巧,当然,实现的方法不唯一。在开始之前,你需要将的当前环境切换为「本地Mock」或「云端Mo
Stella981 Stella981
3年前
PowerMock单元测试
   在Java(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Flib.csdn.net%2Fbase%2Fjavaee)程序的单元测试中常用的mock工具有Mockito和EasyMock。但是这两种mock工具都无法实现对静态、final、私有方法或类的mock。因此有了功能强
Stella981 Stella981
3年前
Mock工具之Mockito实战
在实际项目中写单元测试的过程中我们会发现需要测试的类有很多依赖,这些依赖项又会有依赖,导致在单元测试代码里几乎无法完成构建,尤其是当依赖项尚未构建完成时会导致单元测试无法进行。为了解决这类问题我们引入了Mock的概念,简单的说就是模拟这些需要构建的类或者资源,提供给需要测试的对象使用。业内的Mock工具有很多,也已经很成熟了,这里我们将直接使用最流行的Moc
Easter79 Easter79
3年前
SpringCloud单元测试【六】
SpringCloud的单元测试主要是依靠Mock以及Mockito,所以我们需要对Mock以及Mockito有一定的认识。一、为什么要用MockMvc  可能我们在测试控制层的代码都是启动服务器,在浏览器中输入URL,然后开始测试是否达到预期效果,发生错误的话,修改相关代码并重启服务器再次进行测试。分析一下这个过程,启动服务器打开
Stella981 Stella981
3年前
Mockito模拟进行单元测试
1.1Mockito是什么?    MOCK意思是模拟的意思,主要被用来进行数据的人工组织,不会真正地调用第三方服务器,类似redis,mysql等都不会调用,也不用关心数据底层是如何进行处理的,我们要做的只是将本单元的逻辑进行单元测试,验证数据的逻辑处理性,而其中mock较好的框架就是Mockito。    Mockito是mocking
Stella981 Stella981
3年前
Python unittest模块的使用笔记:对mock.patch()的被mock函数的说明
       现在假设需要对get\_app模块内的create\_app函数做单元测试,同时create\_app函数调用了另一模块utils的load\_yaml函数。由于模块utils的load\_yaml函数可能处于开发阶段或是需要通过网络传输数据,从而导致测试的不便。这时就需要对load\_yaml做一个mock.patch,即伪造一个load\_
Stella981 Stella981
3年前
Mock方法介绍
1现有的单元测试框架单元测试是保证程序正确性的一种有效的测试手段,对于不同的开发语言,通常都能找到相应的单元框架。!(http://img1.51cto.com/attachment/201112/191839171.jpg)(https://www.oschina.net/action/GoToLink?urlhttp%3A%