跳转到主要内容
版本:26.倍

人工模拟

手动模拟用于使用模拟数据消除功能。例如,您可能希望创建一个允许使用假数据的手动模拟,而不是访问网站或数据库等远程资源。这将确保您的测试将是快速的,而不是不稳定的。

模拟用户模块#

手动模拟是通过在__mocks__ /紧挨着模块的子目录。例如,要模拟一个被调用的模块用户模型目录,创建一个名为user.js把它放进模型/ __mocks__目录中。请注意,__mocks__文件夹是区分大小写的,因此命名目录__MOCKS__会破坏一些系统。

当我们在测试中需要该模块时,显式调用jest.mock (' / moduleName’)。要求

模拟节点模块#

如果你正在模拟的模块是一个节点模块(例如:lodash)时,应将mock放置在__mocks__目录相邻node_modules(除非你配置以指向项目根目录以外的文件夹)自动嘲笑。不需要显式调用jest.mock(“module_name”)

限定范围的模块(也称为范围包)可以通过在与作用域模块名称匹配的目录结构中创建文件来进行模拟。例如,要模拟一个有作用域的模块@scope /项目名称,创建一个文件__mocks__ / @scope / project-name.js,形成了@scope /相应的目录。

警告:如果我们想模拟Node的核心模块(例如:fs路径),然后显式地调用jest.mock(路径)要求,因为默认情况下核心节点模块是不被模拟的。

例子#

├──配置
├──__mocks__
│└──fs.js
├──模型
│├──__mocks__
││├─ramstein(2)——cat sound效果器整理www.catsound.js
│└──user.js
├──node_modules
└──的观点

当给定模块存在手动模拟时,Jest的模块系统将在显式调用时使用该模块jest.mock(“moduleName”)。然而,当automock被设置为真正的,将使用手动模拟实现,而不是自动创建的模拟,即使jest.mock(“moduleName”)不叫。要选择退出此行为,您需要显式调用jest.unmock(“moduleName”)在测试中,应该使用实际的模块实现。

注意:为了恰当地嘲弄,Jest需要jest.mock(“moduleName”)在同一个作用域中要求/导入声明。

下面是一个精心设计的示例,其中我们有一个模块,提供给定目录中所有文件的摘要。在本例中,我们使用内核(内置)fs模块。

/ / FileSummarizer.js
使用严格的 ;
常量 fs = 需要 ( “fs” ) ;
函数 summarizeFilesInDirectorySync ( 目录 ) {
返回 fs readdirSync ( 目录 ) 地图 ( 文件名 = > ( {
目录 ,
文件名 ,
} ) ) ;
}
出口 summarizeFilesInDirectorySync = summarizeFilesInDirectorySync ;

因为我们希望我们的测试能够避免实际碰到磁盘(非常缓慢和脆弱),所以我们为fs模块,扩展自动模拟。我们的手动模拟将实现自定义版本的fs用于测试的api:

/ / __mocks__ / fs.js
使用严格的 ;
常量 路径 = 需要 ( “路径” ) ;
常量 fs = 开玩笑 createMockFromModule ( “fs” ) ;
//这是一个自定义函数,我们的测试可以在设置期间使用它来指定
//“模拟”文件系统上的文件应该是什么样子的
//使用' fs ' api。
mockFiles = 对象 创建 ( ) ;
函数 __setMockFiles ( newMockFiles ) {
mockFiles = 对象 创建 ( ) ;
( 常量 文件 newMockFiles ) {
常量 dir = 路径 目录名 ( 文件 ) ;
如果 ( ! mockFiles ( dir ] ) {
mockFiles ( dir ] = ( ] ;
}
mockFiles ( dir ] ( 路径 basename ( 文件 ) ) ;
}
}
//一个自定义版本的' readdirSync ',从特殊的模拟出来
//通过__setMockFiles设置文件列表
函数 readdirSync ( directoryPath ) {
返回 mockFiles ( directoryPath ] || ( ] ;
}
fs __setMockFiles = __setMockFiles ;
fs readdirSync = readdirSync ;
模块 出口 = fs ;

现在我们编写我们的测试。注意,我们需要明确地告知我们想要模仿fs模块,因为它是一个核心节点模块:

/ / __tests__ / FileSummarizer-test.js
使用严格的 ;
开玩笑 模拟 ( “fs” ) ;
描述 ( “listFilesInDirectorySync” , ( ) = > {
常量 MOCK_FILE_INFO = {
“/道路/ / file1.js” : ”控制台。日志(“file1内容”),“ ,
“/道路/ / file2.txt” : “file2内容” ,
} ;
beforeEach ( ( ) = > {
//在每个测试之前设置一些模拟文件信息
需要 ( “fs” ) __setMockFiles ( MOCK_FILE_INFO ) ;
} ) ;
测试 ( '包括摘要目录中的所有文件' , ( ) = > {
常量 FileSummarizer = 需要 ( “. . / FileSummarizer” ) ;
常量 fileSummary = FileSummarizer summarizeFilesInDirectorySync (
' /路径/ ' ,
) ;
预计 ( fileSummary 长度 ) 托比 ( 2 ) ;
} ) ;
} ) ;

这里显示的示例mock使用jest.createMockFromModule生成自动模拟,并覆盖其默认行为。这是推荐的方法,但完全是可选的。如果您根本不想使用自动模拟,您可以从模拟文件导出自己的函数。完全手动模拟的一个缺点是它们是手动的——这意味着当它们模拟的模块发生变化时,您必须手动更新它们。正因为如此,最好在自动模拟能够满足您的需要时使用或扩展它。

为了确保手动模拟和它的实际实现保持同步,可能需要使用实际模块jest.requireActual (moduleName)在您的手动模拟中,并在导出它之前使用模拟函数修改它。

这个例子的代码可以在下面找到例子/ manual-mocks

使用ES模块导入#

如果您正在使用ES模块进口那么你通常会倾向于把你的进口测试文件顶部的语句。但通常需要在模块使用mock之前指示Jest使用mock。因此,Jest会自动提升jest.mock调用模块的顶部(在任何导入之前)。要了解更多信息并查看它的实际操作,请参见这种回购

没有在JSDOM中实现的模拟方法#

如果某些代码使用了JSDOM (Jest使用的DOM实现)还没有实现的方法,则很难对其进行测试。这是一个例子window.matchMedia ()。Jest的回报TypeError:窗口。matchMedia是not a function没有正确地执行测试。

在这种情况下,是嘲笑matchMedia在测试文件中应该解决这个问题:

对象 defineProperty ( 窗口 , “matchMedia” , {
可写的 : 真正的 ,
价值 : 开玩笑 fn ( ) mockImplementation ( 查询 = > ( {
匹配 : ,
媒体 : 查询 ,
onchange : ,
addListener : 开玩笑 fn ( ) , / /弃用
removeListener : 开玩笑 fn ( ) , / /弃用
addEventListener : 开玩笑 fn ( ) ,
removeEventListener : 开玩笑 fn ( ) ,
dispatchEvent : 开玩笑 fn ( ) ,
} ) ) ,
} ) ;

这是如果window.matchMedia ()在测试中调用的函数(或方法)中使用。如果window.matchMedia ()在被测试的文件中直接执行时,Jest报告同样的错误。在这种情况下,解决方案是将手动模拟移动到一个单独的文件中,并在测试中包含这个文件之前测试文件:

进口 ”。/ matchMedia.mock ' ; //必须在测试文件之前导入
进口 { myMethod } ”。/ file-to-test ' ;
描述 ( “myMethod()” , ( ) = > {
//在这里测试方法…
} ) ;
最后一次更新在通过Raj Rajhans