轉載位址
React 16 Jest ES6 Class Mocks(使用ES6文法類的模拟) 執行個體三、四
項目初始化
git clone https:// github.com/durban89/webpack4-react16-reactrouter-demo.git
cd webpack4-react16-reactrouter-demo
git fetch origin
git checkout v_1.0.31
npm install
ES6 Class Mocks(使用ES6文法類的模拟)
Jest可用于模拟導入到要測試的檔案中的ES6文法的類。
ES6文法的類是具有一些文法糖的構造函數。是以,ES6文法的類的任何模拟都必須是函數或實際的ES6文法的類(這也是另一個函數)。
是以可以使用模拟函數來模拟它們。如下
ES6文法類的執行個體
這裡的執行個體我使用官方的例子,SoundPlayer類和SoundPlayerConsumer消費者類。下面部分檔案的内容參考上篇文章
React 16 Jest ES6 Class Mocks(使用ES6文法類的模拟)src/lib/sound-player.js
export default class SoundPlayer {
constructor() {
this.name = 'Player1';
this.fileName = '';
}
choicePlaySoundFile(fileName) {
this.fileName = fileName;
}
playSoundFile() {
console.log('播放的檔案是:', this.fileName);
}
}
src/lib/sound-player-consumer.js
import SoundPlayer from './sound-player';
export default class SoundPlayerConsumer {
constructor() {
this.soundPlayer = new SoundPlayer();
}
play() {
const coolSoundFileName = 'song.mp3';
this.soundPlayer.choicePlaySoundFile(coolSoundFileName);
this.soundPlayer.playSoundFile();
}
}
ES6文法的類測試執行個體三 - 使用子產品工廠參數調用jest.mock()(Calling jest.mock() with the module factory parameter)jest.mock(path,moduleFactory)接受子產品工廠參數。
子產品工廠是一個傳回模拟的函數。
為了模拟構造函數,子產品工廠必須傳回構造函數。
換句話說,子產品工廠必須是傳回函數的函數 - 高階函數(HOF)。測試用例如下
src/__tests__/jest_sound_player_3.test.js
import SoundPlayer from '../lib/sound-player';
import SoundPlayerConsumer from '../lib/sound-player-consumer';
jest.mock('../lib/sound-player'); // SoundPlayer 現在是一個模拟構造函數
const mockPlaySoundFile = jest.fn();
const mockChoicePlaySoundFile = jest.fn();
jest.mock('../lib/sound-player', () => jest.fn().mockImplementation(() => ({
choicePlaySoundFile: mockChoicePlaySoundFile,
playSoundFile: mockPlaySoundFile,
})));
beforeEach(() => {
// 清除所有執行個體并調用構造函數和所有方法:
SoundPlayer.mockClear();
mockChoicePlaySoundFile.mockClear();
});
it('我們可以檢查SoundPlayerConsumer是否調用了類構造函數', () => {
const soundPlayerConsumer = new SoundPlayerConsumer();
expect(SoundPlayer).toHaveBeenCalledTimes(1);
});
it('我們可以檢查SoundPlayerConsumer是否在類執行個體上調用了一個方法', () => {
const soundPlayerConsumer = new SoundPlayerConsumer();
const coolSoundFileName = 'song.mp3';
soundPlayerConsumer.play();
expect(mockChoicePlaySoundFile).toHaveBeenCalledWith(coolSoundFileName);
});
注意上面代碼中的這段代碼
const mockPlaySoundFile = jest.fn();
const mockChoicePlaySoundFile = jest.fn();
jest.mock('../lib/sound-player', () => jest.fn().mockImplementation(() => ({
choicePlaySoundFile: mockChoicePlaySoundFile,
playSoundFile: mockPlaySoundFile,
})));
工廠參數的限制是,由于對jest.mock()的調用被提升到檔案的頂部,是以無法首先定義變量然後在工廠中使用它。
對以"mock"開頭的變量進行例外處理。
ES6文法的類測試執行個體四 - 使用mockImplementation()或mockImplementationOnce()替換mock(Replacing the mock using mockImplementation() or mockImplementationOnce())您可以通過在現有模拟上
調用mockImplementation()來替換前面所有的模拟,以便更改單個測試或所有測試的實作。
對jest.mock的調用被提升到代碼的頂部。
也可以指定模拟,例如在beforeAll()中,通過在現有mock上調用mockImplementation()或mockImplementationOnce()而不是使用factory參數。
如果需要,這還允許在測試之間更改模拟:測試用例如下
import SoundPlayer from '../lib/sound-player';
import SoundPlayerConsumer from '../lib/sound-player-consumer';
jest.mock('../lib/sound-player'); // SoundPlayer 現在是一個模拟構造函數
describe('SoundPlayer被調用的時候抛出異常', () => {
beforeAll(() => {
SoundPlayer.mockImplementation(() => ({
playSoundFile: () => {
throw new Error('Test error');
},
choicePlaySoundFile: () => {
throw new Error('Test error');
},
}));
});
it('play被調用的收抛出異常', () => {
const soundPlayerConsumer = new SoundPlayerConsumer();
expect(() => soundPlayerConsumer.play()).toThrow();
});
});
上面的代碼注意這裡
beforeAll(() => {
SoundPlayer.mockImplementation(() => ({
playSoundFile: () => {
throw new Error('Test error');
},
choicePlaySoundFile: () => {
throw new Error('Test error');
},
}));
});
實踐項目位址
git clone https:// github.com/durban89/webpack4-react16-reactrouter-demo.git
git checkout v_1.0.32