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

ES6クラスのモック

Jestは,テストしたいファイルにインポートしたES6クラスをモックすることもできます。

ES6クラスというのは,いくつかの糖衣構文を加えたコンストラクタ関数です。したがって,ES6クラスのモックは,何らかの関数であるか,もう一つのES6クラス(繰り返しますが,これは別の関数です)になります。そのため,モック関数をを用することでモックを作物

ES6クラスの例#

具体例として,音楽ファイルを再生するクラスSoundPlayerとそのクラスを使用する消費者クラスSoundPlayerConsumerについて考えてみましょう。SoundPlayerConsumerのテスト内で,SoundPlayerクラスをモックするには,次のようなコードを書きます。

/ / sound-player.js
出口 默认的 SoundPlayer {
构造函数 ( ) {
喷火 = “酒吧” ;
}
playSoundFile ( 文件名 ) {
安慰 日志 ( “播放声音文件” + 文件名 ) ;
}
}
/ / sound-player-consumer.js
进口 SoundPlayer “。/留声机” ;
出口 默认的 SoundPlayerConsumer {
构造函数 ( ) {
SoundPlayer. = 新的 SoundPlayer ( ) ;
}
playSomethingCool ( ) {
常量 coolSoundFileName = 'song.mp3' ;
SoundPlayer. playSoundFile ( coolSoundFileName ) ;
}
}

ES6クラスのモックを作る4つの方法#

自动モック#

jest.mock(’。/留声机”)を呼ぶと,便利な”自動モック”を返してくれます。これは,クラスのコンストラクタおよびすべてのメソッドの呼び出しをスパイするのに使用できます。この関数はES6クラスをモックコンストラクタに置き換え,すべてのメソッドを,常に未定义的を返すモック関数に置き換えます。メソッドの呼び出しはtheAutomaticMock.mock.instances .methodName.mock.calls(指数)に保存されます。

クラスクラスでアロー关有关部を使する合,アロー关键モックの一部にはないないということに注意してください。なぜなら,アロー関数はオブジェクトのプロトタイプには現れず,単に関数への参照を保持しているプロパティに過ぎないためです。

クラスの実装を置き換える必要がない場合は,このメソッドを使用するのが最も簡単な選択肢です。例:

进口 SoundPlayer “。/留声机” ;
进口 SoundPlayerConsumer ”。/ sound-player-consumer ' ;
开玩笑 嘲笑 ( “。/留声机” ) ; // SoundPlayer现在是一个模拟构造函数
beforeEach ( ( ) => {
//清除构造函数和方法的所有实例和调用:
SoundPlayer 笨拙 ( ) ;
} ) ;
( 我们可以检查消费者是否调用了类构造函数 , ( ) => {
常量 SoundPlayerConsumer. = 新的 SoundPlayerConsumer ( ) ;
预计 ( SoundPlayer ) toHaveBeenCalledTimes ( 1 ) ;
} ) ;
( 我们可以检查消费者是否在类实例上调用了方法 , ( ) => {
//显示mockClear()工作:
预计 ( SoundPlayer ) toHaveBeenCalled ( ) ;
常量 SoundPlayerConsumer. = 新的 SoundPlayerConsumer ( ) ;
//应该再次调用//构造函数:
预计 ( SoundPlayer ) toHaveBeenCalledTimes ( 1 ) ;
常量 coolSoundFileName = 'song.mp3' ;
SoundPlayerConsumer. playSomethingCool ( ) ;
/ /模拟。实例可以使用自动模拟:
常量 mockSoundPlayerInstance = SoundPlayer 嘲笑 实例 ( 0 ] ;
常量 mockPlaySoundFile = mockSoundPlayerInstance playSoundFile ;
预计 ( mockPlaySoundFile 嘲笑 调用 ( 0 ] ( 0 ] ) toEqual ( coolSoundFileName ) ;
//等价于上面的检查:
预计 ( mockPlaySoundFile ) toHaveBeenCalledWith ( coolSoundFileName ) ;
预计 ( mockPlaySoundFile ) toHaveBeenCalledTimes ( 1 ) ;
} ) ;

マニュアルモック#

マニュアルモックを作用には,モックの包装を__mocks__ディレクトリに保存します。これにより,特定の実装をテストファイル全体で使用することができるようになります。

/ / __mocks__ / sound-player.js
//导入这个命名的导出到你的测试文件:
出口 常量 mockPlaySoundFile = 开玩笑 fn ( ) ;
常量 嘲笑 = 开玩笑 fn ( ) 模仿 ( ( ) => {
返回 { playSoundFile : mockPlaySoundFile } ;
} ) ;
出口 默认的 嘲笑 ;

すべてのインスタンスで共有される,モックとモックメソッドをインポートします。

/ / sound-player-consumer.test.js
进口 SoundPlayer , { mockPlaySoundFile } “。/留声机” ;
进口 SoundPlayerConsumer ”。/ sound-player-consumer ' ;
开玩笑 嘲笑 ( “。/留声机” ) ; // SoundPlayer现在是一个模拟构造函数
beforeEach ( ( ) => {
//清除构造函数和方法的所有实例和调用:
SoundPlayer 笨拙 ( ) ;
mockPlaySoundFile 笨拙 ( ) ;
} ) ;
( 我们可以检查消费者是否调用了类构造函数 , ( ) => {
常量 SoundPlayerConsumer. = 新的 SoundPlayerConsumer ( ) ;
预计 ( SoundPlayer ) toHaveBeenCalledTimes ( 1 ) ;
} ) ;
( 我们可以检查消费者是否在类实例上调用了方法 , ( ) => {
常量 SoundPlayerConsumer. = 新的 SoundPlayerConsumer ( ) ;
常量 coolSoundFileName = 'song.mp3' ;
SoundPlayerConsumer. playSomethingCool ( ) ;
预计 ( mockPlaySoundFile ) toHaveBeenCalledWith ( coolSoundFileName ) ;
} ) ;

jest.mock ()をモジュールファクトリファクトリ数で呼ぶ#

jest.mock(path, moduleFactory)モジュールファクトリ引数を取ります。モジュールファクトリとは,モックを返す関数のことです。

コンストラクタ関数をモックするためには,モジュールファクトリはコンストラクタ関数を返さなければなりません。言い換えると,モジュールファクトリは関数を返す関数,つまり高階関数(高阶函数;霍夫)でなければなりません。

进口 SoundPlayer “。/留声机” ;
常量 mockPlaySoundFile = 开玩笑 fn ( ) ;
开玩笑 嘲笑 ( “。/留声机” , ( ) => {
返回 开玩笑 fn ( ) 模仿 ( ( ) => {
返回 { playSoundFile : mockPlaySoundFile } ;
} ) ;
} ) ;

ファクトリファクトリ数の制制,jest.mock ()が呼ばれるのがファイルの先頭であるため,最初に変数を定義してからファクトリの中で使うことができないことです。そのため,“模拟”から始まる名前の変数は例外となっています。それらの変数を初期化することは,あなたの責任です。例えば,変数宣言の中で“模拟”の代わりに‘假’を使用すると,次のようなエラーが発生します。

/ /注意:これは失敗します
进口 SoundPlayer “。/留声机” ;
常量 fakePlaySoundFile = 开玩笑 fn ( ) ;
开玩笑 嘲笑 ( “。/留声机” , ( ) => {
返回 开玩笑 fn ( ) 模仿 ( ( ) => {
返回 { playSoundFile : fakePlaySoundFile } ;
} ) ;
} ) ;

mockImplementation ()またはmockImplementationOnce ()を使用したモックを置き換える#

以上すべてのモックで実装を変更するには,1つのテストまたはすべてのテストに対して,既存のモックの中でmockImplementation ()ををます。

jest.mockの呼び出しはコードトップに引き上げられ。たとえばbeforeAll ()の中などで後からモックを指定するには,ファクトリ引数で指定するのではなく,mockImplementation ()(またはmockImplementationOnce ())を既存のモックの中で呼び出します。これにより,テスト間で必要に応じてモックを変更することができるようになります。

进口 SoundPlayer “。/留声机” ;
进口 SoundPlayerConsumer ”。/ sound-player-consumer ' ;
开玩笑 嘲笑 ( “。/留声机” ) ;
描述 ( "当SoundPlayer抛出错误时" , ( ) => {
beforeAll ( ( ) => {
SoundPlayer 模仿 ( ( ) => {
返回 {
playSoundFile : ( ) => {
新的 错误 ( '测试错误' ) ;
} ,
} ;
} ) ;
} ) ;
( '打电话给PlaysometionCooh时应抛出错误' , ( ) => {
常量 SoundPlayerConsumer. = 新的 SoundPlayerConsumer ( ) ;
预计 ( ( ) => SoundPlayerConsumer. playSomethingCool ( ) ) tothrow. ( ) ;
} ) ;
} ) ;

踏み込んだ話:モックコンストラクタ関数を理解する#

コンストラクタ関数を構築する時,.mockImplementation jest.fn () ()。

マニュアルモックは1つのES6クラスである#

__mocks__ディレクトリ内にモッククラスと同じファイル名を使用したES6クラスを定義すると,モックとして機能します。このクラスは実際のクラスの代わりに使われます。これにより,クラスにテスト実装を注入できますが,関数呼び出しをスパイする手段は提供されません。

具体例として,モックは次のようになります。

/ / __mocks__ / sound-player.js
出口 默认的 SoundPlayer {
构造函数 ( ) {
安慰 日志 ( '模拟SoundPlayer:构造函数被称为' ) ;
}
playSoundFile ( ) {
安慰 日志 ( " Mock SoundPlayer: playSoundFile was called " ) ;
}
}

モジュールファクトリパラメータを使使用してモックする#

jest.mock(path, moduleFactory)に渡されたモジュールファクトリ関数は,函数*を返す高階関数にすることもできます。こうすることで,モックに対して新的を呼ぶことができます。繰り返しますが,こうすることで,テストに異なる動作を挿入することができますが,関数の呼び出しをスパイすることはできません。

*モジュールファクトリ関数は関数を返さなければならない#

コンストラクタ関数をモックするためには,モジュールファクトリはコンストラクタ関数を返さなければなりません。言い換えると,モジュールファクトリは関数を返す関数,つまり高階関数(高阶函数;霍夫)でなければなりません。

开玩笑 嘲笑 ( “。/留声机” , ( ) => {
返回 功能 ( ) {
返回 { playSoundFile : ( ) => { } } ;
} ;
} ) ;

注意:アロー关圈机能しん

javascriptでは,新的をアロー関数に対して使用できないからです。そのため,以下のような関数は動作しません。

开玩笑 嘲笑 ( “。/留声机” , ( ) => {
返回 ( ) => {
//不能工作;箭头函数不能用new调用
返回 { playSoundFile : ( ) => { } } ;
} ;
} ) ;

このように書くと,babel-preset-envなどでES5にトランスパイルしない限り,_soundPlayer2.default不是构造函数という例外が発生します。(ES5にはアロー関数やクラスが存在しないため,両方とも単純な関数に変換されるためです。

使用状況をトラックし続ける(モックをスパイする)#

テストの実装を注入するのは便利ですが,おそらく,クラスのコンストラクタやメソッドが正しい引数で呼ばれたかどうかも確認したいと考えるでしょう。

コンストラクタをスパイする#

コンストラクタの呼び出しを追跡するには,高階関数が返す関数をJestのモック関数に置換します。モック関数はjest.fn()で作用ことができ,关键词包装はmockImplementation ()で指定します。

进口 SoundPlayer “。/留声机” ;
开玩笑 嘲笑 ( “。/留声机” , ( ) => {
//工作并允许您检查构造函数调用:
返回 开玩笑 fn ( ) 模仿 ( ( ) => {
返回 { playSoundFile : ( ) => { } } ;
} ) ;
} ) ;

これにより,SoundPlayer.mock.calls:期待(SoundPlayer).tohavebeencalled();または,それと同等のコード期望(SoundPlayer.mock.calls.length) .toEqual (1);によってモッククラスの使用状況が確認できます。

模拟非默认类导出#

クラスがモジュールからのデフォルトのエクスポートではない場合,クラスのエクスポート名と同じキーを持つオブジェクトを返す必要があります。

进口 { SoundPlayer } “。/留声机” ;
开玩笑 嘲笑 ( “。/留声机” , ( ) => {
//机械するするコンストラクターコンストラクターのが确认できます:
返回 {
SoundPlayer : 开玩笑 fn ( ) 模仿 ( ( ) => {
返回 { playSoundFile : ( ) => { } } ;
} ) ,
} ;
} ) ;

クラスのメソッドをスパイする#

モッククラスは,任意のメンバー関数(コード例ではplaySoundFile)を提供する必要があります。もし必要な関数がなければ,存在しない関数を呼び出した時にエラーが起こります。しかし,おそらく期待通りの引数で呼び出されたことを確認するために,これらのメソッドの呼び出しに対してもスパイしたいと考えるでしょう。

テスト中は,モックコンストラクタ関数が呼ばれるたびに,新しいオブジェクトが作られます。これらすべてのオブジェクトのメソッドの呼び出しをスパイするために,playSoundFileとその他のモック関数を作成し,テスト中に利用できるようにその同一のモック関数への参照を保存しておきます。

进口 SoundPlayer “。/留声机” ;
常量 mockPlaySoundFile = 开玩笑 fn ( ) ;
开玩笑 嘲笑 ( “。/留声机” , ( ) => {
返回 开玩笑 fn ( ) 模仿 ( ( ) => {
返回 { playSoundFile : mockPlaySoundFile } ;
//现在我们可以跟踪对playsoundfile的调用
} ) ;
} ) ;

このコードと同等のマニュアルモックは,次のように書けるでしょう。

/ / __mocks__ / sound-player.js
//将这个命名的导出导入到您的测试文件
出口 常量 mockPlaySoundFile = 开玩笑 fn ( ) ;
常量 嘲笑 = 开玩笑 fn ( ) 模仿 ( ( ) => {
返回 { playSoundFile : mockPlaySoundFile } ;
} ) ;
出口 默认的 嘲笑 ;

使用例は,モジュールファクトリ関数と同様ですが,jest.mock ()の第2引数を省略することができる点と,モックしたメソッドがテストファイル内にはないので,それをインポートする必要がある点が異なります。__mocks__を含まない,オリジナルのモジュールパスを使しください。

テスト間でのクリーンアップ#

モックコンストラクタ関数とメソッドの呼び出しの記録をクリアするには,mockClear ()beforeEach ()関数の中で呼びます。

beforeEach ( ( ) => {
SoundPlayer 笨拙 ( ) ;
mockPlaySoundFile 笨拙 ( ) ;
} ) ;

完全に动作するコード例#

以下に完全に動作するテストファイルの例を挙げます。このコードでは,jest.mockに対してモジュールファクトリ引数を与えています。

/ / sound-player-consumer.test.js
进口 SoundPlayer “。/留声机” ;
进口 SoundPlayerConsumer ”。/ sound-player-consumer ' ;
常量 mockPlaySoundFile = 开玩笑 fn ( ) ;
开玩笑 嘲笑 ( “。/留声机” , ( ) => {
返回 开玩笑 fn ( ) 模仿 ( ( ) => {
返回 { playSoundFile : mockPlaySoundFile } ;
} ) ;
} ) ;
beforeEach ( ( ) => {
SoundPlayer 笨拙 ( ) ;
mockPlaySoundFile 笨拙 ( ) ;
} ) ;
( “消费者应该能够在SoundPlayer上调用新() , ( ) => {
常量 SoundPlayerConsumer. = 新的 SoundPlayerConsumer ( ) ;
//确保构造函数创建对象:
预计 ( SoundPlayerConsumer. ) toBeTruthy ( ) ;
} ) ;
( 我们可以检查消费者是否调用了类构造函数 , ( ) => {
常量 SoundPlayerConsumer. = 新的 SoundPlayerConsumer ( ) ;
预计 ( SoundPlayer ) toHaveBeenCalledTimes ( 1 ) ;
} ) ;
( 我们可以检查消费者是否在类实例上调用了方法 , ( ) => {
常量 SoundPlayerConsumer. = 新的 SoundPlayerConsumer ( ) ;
常量 coolSoundFileName = 'song.mp3' ;
SoundPlayerConsumer. playSomethingCool ( ) ;
预计 ( mockPlaySoundFile 嘲笑 调用 ( 0 ] ( 0 ] ) toEqual ( coolSoundFileName ) ;
} ) ;