跳到主要内容
版本:26.x.

ИмитаторыклассовES6

JestМожетИспользоватьсядлясозданияИмитаторовКлассовES6,Импортируемыхвфайлы,Которыевыжелаетепротестировать。

КлассыSes6вляштсяфункциями-конструкторамиснекоторымсинтаксическимсахаром。Поштомулюбойобъект-имитатордляклассаSes6ДолженБытьфункциейилифактиейилифактическимКлассомES6(Который,ВСвоюОчередь,Такжеявляетсяфункцией)。ТакимОбразом,Выможетеимитироватьповедение,ИспользуяФункциисозданияИмитаторов

ПримерКлассаSE6.

Мыбудемиспользоватьпримеркласса,Которыйвоспроизводитзвуковыефайлы,КлассS音乐游戏,ИпотребительскийКласс,Которыйиспользуетэтоткласс,SoundPlayerConsumer.。МысоздадимимитатордляSoundPlayer.внашихтестахдляSoundPlayerConsumer.

// sound-player.js
出口 默认 班级 SoundPlayer. {
构造函数 {
这个 Foo = '酒吧' ;
}
playsoundfile. 文件名 {
安慰 日志 '玩声音文件' + 文件名 ;
}
}
// sound-player-confiecer.js
进口 SoundPlayer. './sound-player' ;
出口 默认 班级 SoundPlayerConsumer. {
构造函数 {
这个 SoundPlayer. = 新的 SoundPlayer. ;
}
Playsometingcool. {
const coolsoundfilename. = 'song.mp3' ;
这个 SoundPlayer. playsoundfile. coolsoundfilename. ;
}
}

4способасозданияИмитатораКлассаES6

Автоматическийимитатор.

Зовуший.шутка.издеваться。'(/ sound-player')возврашаетполезный“Автоматическиймакет”,КоторыйможноИспользоватьдляотслеживаниявызововКонструктораклассаивсехегоМетодов。ОнзаменитКлассSES6НаКонструкторимитатора,АТакжезаменитвсеегоМетодыMock-функциями.,всегдавозврашашими.不明确的。方法调用保存在theautomaticmock.mock.instances [index] .methodname.mock.calls

请注意,如果您在课程中使用箭头函数,则会不是成为模拟的一部分。因此,对象的原型上不存在箭头函数,它们仅仅是对功能的引用的属性。

ЕсливамненужнозаменятьреализациюКласса,этосамыйпростойвариантдлянастройки。Например:

进口 SoundPlayer. './sound-player' ;
进口 SoundPlayerConsumer. './sound-player-consumer' ;
笑话 嘲笑 './sound-player' ; // SoundPlayer现在是模拟构造函数
摘要 => {
//清除所有实例并调用构造函数和所有方法:
SoundPlayer. 笨拙 ;
} ;
“我们可以检查消费者是否称为类构造函数' => {
const SoundPlayerConsumer. = 新的 SoundPlayerConsumer. ;
预计 SoundPlayer. tohavebeencalledtimes. 1 ;
} ;
“我们可以检查Class实例上的消费者是否称为方法' => {
//显示MockClear()正在工作:
预计 SoundPlayer. 不是 TohaveBeencalled. ;
const SoundPlayerConsumer. = 新的 SoundPlayerConsumer. ;
//应该再次调用//构造函数:
预计 SoundPlayer. tohavebeencalledtimes. 1 ;
const coolsoundfilename. = 'song.mp3' ;
SoundPlayerConsumer. Playsometingcool. ;
// mock.instances可用自动模拟:
const MockSoundPlayerInstance. = SoundPlayer. 嘲笑 实例 [ 0. ] ;
const 模仿oundfile. = MockSoundPlayerInstance. playsoundfile. ;
预计 模仿oundfile. 嘲笑 呼叫 [ 0. ] [ 0. ] toequal. coolsoundfilename. ;
//相当于上述检查:
预计 模仿oundfile. Tohavebeencalledwith. coolsoundfilename. ;
预计 模仿oundfile. tohavebeencalledtimes. 1 ;
} ;

Создаваемыевручнушимитаторы.

创建一个手动模拟通过保存模拟实现__mocks__文件夹。этопозволяетуказатьреализациюиииспользоватьеевтестовыхфайлах。

// __mocks __ / sound-player.js
//Импортируйтетештотименованныйобъектвсвойфайлстестом:
出口 const 模仿oundfile. = 笑话 FN. ;
const 嘲笑 = 笑话 FN. 模仿 => {
返回 { playsoundfile. 模仿oundfile. } ;
} ;
出口 默认 嘲笑 ;

ИмпортируйтемакетиметодМакета,СовместноИспользуемыевсемиэкземплярами:

// sound-player-configer.test.js
进口 SoundPlayer. { 模仿oundfile. } './sound-player' ;
进口 SoundPlayerConsumer. './sound-player-consumer' ;
笑话 嘲笑 './sound-player' ; // SoundPlayer现在是模拟构造函数
摘要 => {
//清除所有实例并调用构造函数和所有方法:
SoundPlayer. 笨拙 ;
模仿oundfile. 笨拙 ;
} ;
“我们可以检查消费者是否称为类构造函数' => {
const SoundPlayerConsumer. = 新的 SoundPlayerConsumer. ;
预计 SoundPlayer. tohavebeencalledtimes. 1 ;
} ;
“我们可以检查Class实例上的消费者是否称为方法' => {
const SoundPlayerConsumer. = 新的 SoundPlayerConsumer. ;
const coolsoundfilename. = 'song.mp3' ;
SoundPlayerConsumer. Playsometingcool. ;
预计 模仿oundfile. Tohavebeencalledwith. coolsoundfilename. ;
} ;

打电话jest.mock()使用模块出厂参数

jest.mock(路径,modulefactory)需要一个模块工厂争论。模块工厂是一个返回模拟的函数。

чтобыиздеватьсянадфункциейконструктора,Фабрикамора,ФабрикамодулейдолжнавозврашатьфункциюКонструктора。Другимисловами,ФабрикамодулейДолжнаБытьфункцией,КотораявозвращаетФункцию-функциюБолеевысокогопорядка(HOF)。

进口 SoundPlayer. './sound-player' ;
const 模仿oundfile. = 笑话 FN. ;
笑话 嘲笑 './sound-player' => {
返回 笑话 FN. 模仿 => {
返回 { playsoundfile. 模仿oundfile. } ;
} ;
} ;

ОграничениеСПараметром工厂Таково,ТакКаквызовышутка.издеваться()Поднимаштсякверхнейчастифайла,Невозможноснечалаопределитьпеременную,Азатемиспользоватьевфабрике。Исключениесоставляютпеременные,Которыеначинаштсясослова“Полка”。этододовас,чтобыгарантировать,чтоонибудутинициализированывововремя!例如,由于使用“假”而不是“变量声明”而不是“Mock”,以下将抛出范围超出错误:

//注意:这将失败
进口 SoundPlayer. './sound-player' ;
const fakeplysoundfile. = 笑话 FN. ;
笑话 嘲笑 './sound-player' => {
返回 笑话 FN. 模仿 => {
返回 { playsoundfile. fakeplysoundfile. } ;
} ;
} ;

用mock替换使用模仿()或者模仿once()

Выможетезаменитьвсеперечисленноевысмеиваетсядлятого,чтобыизменитьреализацию,Наодинтестилитесты,потелефону>模仿()насушествушеммакете。

Вызываетшутку.макетыподнимаштсянаверхкода。您可以在稍后指定模拟,例如:在beforeall(),通过致电模仿()(或者模仿once())在现有模拟而不是使用工厂参数。штотакжепозволяетпринеобходимостиизменитьмакетМеждутестами:

进口 SoundPlayer. './sound-player' ;
进口 SoundPlayerConsumer. './sound-player-consumer' ;
笑话 嘲笑 './sound-player' ;
描述 '当SoundPlayer抛出错误时' => {
Beforeall. => {
SoundPlayer. 模仿 => {
返回 {
playsoundfile. => {
新的 错误 '测试错误' ;
}
} ;
} ;
} ;
'打电话给PlaysometionCooh时应抛出错误' => {
const SoundPlayerConsumer. = 新的 SoundPlayerConsumer. ;
预计 => SoundPlayerConsumer. Playsometingcool. tothrow. ;
} ;
} ;

ВГлубину:ПониманиефункцийсозданияИмитаторов

ПостроениеМакетафункцииконструктораспомошьюэст.сноска。)(模仿()Делаетнасмешкиболеесложными,чемониестьнасамомделе。本节展示了如何创建自己的模型,以说明如何嘲弄作品。

РучнойМакет,КоторыйявляетсядругимКлассомES6

如果使用与映射类相同的文件名定义ES6类__mocks__文件夹,它将作为模拟。◄тотклассбудетиспользоватьсявместореаальногоКласса。этопозволяетвнедритьреализациюТестадлякласса,Нонепредоставляетспособшпионитьзавызовами。

длянадуманногоПримераМакетМожетВыглядетьследушимобразом:

// __mocks __ / sound-player.js
出口 默认 班级 SoundPlayer. {
构造函数 {
安慰 日志 '模拟SoundPlayer:构造函数被称为' ;
}
playsoundfile. {
安慰 日志 '模拟SoundPlayer:PlaySoundFile被称为' ;
}
}

模块使用模块出厂参数

ПереданнаяФункцияФабрикиМодуляКшутка.макет(Путь,modulfactory)МожетБытьHOF,Которыйвозврашаетфункцию*。这将允许呼叫新的在模拟上。同样,这允许您注入不同的测试行为进行测试,但不提供侦听呼叫的方法。

*模块出厂功能必须返回函数

чтобыиздеватьсянадфункциейконструктора,Фабрикамора,ФабрикамодулейдолжнавозврашатьфункциюКонструктора。Другимисловами,ФабрикамодулейДолжнаБытьфункцией,КотораявозвращаетФункцию-функциюБолеевысокогопорядка(HOF)。

笑话 嘲笑 './sound-player' => {
返回 功能 {
返回 { playsoundfile. => { } } ;
} ;
} ;

注意:箭头函数不起作用

请注意,模拟不能是箭头函数,因为调用新的在JavaScript中不允许在箭头函数上。所以这不起作用:

笑话 嘲笑 './sound-player' => {
返回 => {
//不起作用;箭头函数无法用新的函数调用
返回 { playsoundfile. => { } } ;
} ;
} ;

这将抛出typeerror:_soundplayer2.default不是构造函数,除非代码被转移到ES5,例如ES5。经过@ Babel / Preset-Env。(ES5没有箭头函数也没有类,因此两者都将被转发到普通功能。)

跟踪用法轨道(在模拟中窥探)

注入测试实现是有帮助的,但您可能还想测试是否以正确的参数调用类构造函数亚搏取款和方法。

窥探构造函数

为了跟踪对构造函数的调用,替换Hof返回的函数与Jest模拟功能。创建它jest.fn(),然后指定其实现模仿()

进口 SoundPlayer. './sound-player' ;
笑话 嘲笑 './sound-player' => {
//工作并允许您检查构造函数调用:
返回 笑话 FN. 模仿 => {
返回 { playsoundfile. => { } } ;
} ;
} ;

这将让我们在使用时检查我们的嘲弄类的用法soundplayer.mock.calls.期待(SoundPlayer).tohavebeencalled();或接近等同的:期待(soundplayer.mock.calls.length).toequal(1);

嘲笑非默认类出口

如果类是不是从模块中导出的默认导出,那么您需要将对象返回与类导出名称相同的键。

进口 { SoundPlayer. } './sound-player' ;
笑话 嘲笑 './sound-player' => {
//工作并允许您检查构造函数调用:
返回 {
SoundPlayer. 笑话 FN. 模仿 => {
返回 { playsoundfile. => { } } ;
}
} ;
} ;

窥探我们班级的方法

我们的嘲弄课程需要提供任何成员职能(playsoundfile.在该示例中)将在我们的测试期间调用,否则我们将获得错误调用不存在的函数的错误。但我们可能希望在对这些方法的呼叫中窥探,以确保它们被预期的参数调用。

每次测试期间调用Mock构造函数函数时,将创建一个新对象。我们填充了所有这些对象的方法调用playsoundfile.使用另一个模拟功能,并在测试文件中存储对同一模拟功能的引用,因此在测试期间可用。

进口 SoundPlayer. './sound-player' ;
const 模仿oundfile. = 笑话 FN. ;
笑话 嘲笑 './sound-player' => {
返回 笑话 FN. 模仿 => {
返回 { playsoundfile. 模仿oundfile. } ;
//现在我们可以跟踪对playsoundfile的调用
} ;
} ;

手动模拟相当于这将是:

// __mocks __ / sound-player.js
//将此命名导出导入测试文件
出口 const 模仿oundfile. = 笑话 FN. ;
const 嘲笑 = 笑话 FN. 模仿 => {
返回 { playsoundfile. 模仿oundfile. } ;
} ;
出口 默认 嘲笑 ;

用法与模块出厂函数类似,除了您可以从中省略第二个参数jest.mock(),并且您必须将模拟方法导入测试文件,因为它不再在那里定义。使用原始模块路径;不包括__mocks__

在测试之间清理

要清除调用模拟构造函数及其方法的呼叫记录,我们调用MockClear()在里面前提()功能:

摘要 => {
SoundPlayer. 笨拙 ;
模仿oundfile. 笨拙 ;
} ;

完整的例子

这是一个完整的测试文件,它使用模块出厂参数jest.mock.

// sound-player-configer.test.js
进口 SoundPlayer. './sound-player' ;
进口 SoundPlayerConsumer. './sound-player-consumer' ;
const 模仿oundfile. = 笑话 FN. ;
笑话 嘲笑 './sound-player' => {
返回 笑话 FN. 模仿 => {
返回 { playsoundfile. 模仿oundfile. } ;
} ;
} ;
摘要 => {
SoundPlayer. 笨拙 ;
模仿oundfile. 笨拙 ;
} ;
“消费者应该能够在SoundPlayer上调用新() => {
const SoundPlayerConsumer. = 新的 SoundPlayerConsumer. ;
//确保构造函数创建了对象:
预计 SoundPlayerConsumer. Tobeththy. ;
} ;
“我们可以检查消费者是否称为类构造函数' => {
const SoundPlayerConsumer. = 新的 SoundPlayerConsumer. ;
预计 SoundPlayer. tohavebeencalledtimes. 1 ;
} ;
“我们可以检查Class实例上的消费者是否称为方法' => {
const SoundPlayerConsumer. = 新的 SoundPlayerConsumer. ;
const coolsoundfilename. = 'song.mp3' ;
SoundPlayerConsumer. Playsometingcool. ;
预计 模仿oundfile. 嘲笑 呼叫 [ 0. ] [ 0. ] toequal. coolsoundfilename. ;
} ;