React16JestES6ClassMocks(使用ES6語法類的模擬)例項一

durban發表於2018-07-14

轉載地址

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.29
npm install

ES6 Class Mocks(使用ES6語法類的模擬)

Jest可用於模擬匯入到要測試的檔案中的ES6語法的類。

ES6語法的類是具有一些語法糖的建構函式。因此,ES6語法的類的任何模擬都必須是函式或實際的ES6語法的類(這也是另一個函式)。
所以可以使用模擬函式來模擬它們。如下

一個ES6語法類的例項

這裡的例項我使用官方的例子,SoundPlayer類和SoundPlayerConsumer消費者類。

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語法的類測試,今天先使用第一種方式 – 自動模擬(Automatic mock)

呼叫jest.mock(`../lib/sound-player`)會返回一個有用的“自動模擬”,可以使用它來監視對類建構函式及其所有方法的呼叫。
它用模擬建構函式替換ES6語法的類,並使用總是返回undefined的mock函式替換它的所有方法。
方法呼叫儲存在AutomaticMock.mock.instances [index] .methodName.mock.calls中。
請注意,如果在類中使用箭頭功能,它們將不會成為模擬的一部分。
原因是箭頭函式不存在於物件的原型上,它們只是包含對函式的引用的屬性。
如果不需要替換類的實現,這是最簡單的設定選項。測試用例如下:

src/__tests__/jest_sound_player.test.js

import SoundPlayer from `../lib/sound-player`;
import SoundPlayerConsumer from `../lib/sound-player-consumer`;

jest.mock(`../lib/sound-player`); // SoundPlayer 現在是一個模擬建構函式

beforeEach(() => {
  // 清除所有例項並呼叫建構函式和所有方法:
  SoundPlayer.mockClear();
});

it(`我們可以檢查SoundPlayerConsumer是否呼叫了類建構函式`, () => {
  const soundPlayerConsumer = new SoundPlayerConsumer();
  expect(SoundPlayer).toHaveBeenCalledTimes(1);
});

it(`我們可以檢查SoundPlayerConsumer是否在類例項上呼叫了一個方法`, () => {
  // 檢查 mockClear() 會否起作用:
  expect(SoundPlayer).not.toHaveBeenCalled();

  const soundPlayerConsumer = new SoundPlayerConsumer();
  // 類建構函式再次被呼叫
  expect(SoundPlayer).toHaveBeenCalledTimes(1);

  const coolSoundFileName = `song.mp3`;
  soundPlayerConsumer.play();

  // mock.instances可用於自動模擬
  const mockSoundPlayerInstance = SoundPlayer.mock.instances[0];
  const mockChoicePlaySoundFile = mockSoundPlayerInstance.choicePlaySoundFile;
  expect(mockChoicePlaySoundFile.mock.calls[0][0]).toEqual(coolSoundFileName);
  // 相當於上面的檢查
  expect(mockChoicePlaySoundFile).toHaveBeenCalledWith(coolSoundFileName);
  expect(mockChoicePlaySoundFile).toHaveBeenCalledTimes(1);
});

執行會得到類似如下輸出

 PASS  src/__tests__/jest_sound_player.test.js
   我們可以檢查SoundPlayerConsumer是否呼叫了類建構函式 (4ms)
   我們可以檢查SoundPlayerConsumer是否在類例項上呼叫了一個方法 (3ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        2.27s
Ran all test suites matching /src/__tests__/jest_sound_player.test.js/i.

下次介紹第二種方法 – 手動模擬(Manual mock)

實踐專案地址

git clone https://github.com/durban89/webpack4-react16-reactrouter-demo.git
git checkout v_1.0.30


相關文章