React 16 Jest ES6 Class Mocks(使用ES6语法类的模拟) 实例一

转载地址

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

上一篇:React 16 之 测试单元(Jest+React+Enzyme)


下一篇:实验:基于语句复制的不安全性《MySQL排错指南Page83-85》