如何模拟在测试类中创建的API客户端?

时间:2019-05-20 04:09:35

标签: node.js jasmine jestjs sinon

我有一个下面的组件类,该组件类使用第三方npm模块创建其余和websocket连接。我可以将Component.constructor更改为接受模块作为依赖项,以便在Jest测试期间注入模拟版本。但是我读到有关用Jest制作Mocks的文章,我想我想尝试一下,但似乎无法理解如何截获Api.Rest()和Api.Websocket返回值。

// component.ts
import * as Api from 'npm-module'
import * as wait from 'wait-for-stuff' // actual npm module
export class Component {
    private _rest:any;
    private _websocket:any;
    public events = new EventEmitter();
    constructor() {
        // I want to intecept the return value of
        // Api.Rest() and Api.Websocket() to use mock versions.
        this._rest = new Api.Rest();
        this._websocket = new Api.Websocket();

        this._init();
    }

    private _init() {
        // so that when do stuff with this._rest and this._websocket;
        // I can control what is the expected results during test
        this._websocket.onUpdate((data) => {
            events.emit('update', data);
        });
        var value = wait.for.promise(this._rest.getSomething());
    }
}

我是否必须使用Sinon或Jasmine等其他测试库?

1 个答案:

答案 0 :(得分:2)

以下是一个简化的工作示例,可以帮助您入门:

// @ts-ignore
import * as Api from 'npm-module';  // <= (ts-ignore since "npm-module" doesn't exist)
import EventEmitter from 'events';

jest.mock('npm-module', () => {
  const getSomethingMock = jest.fn();  // <= always return...
  const onUpdateMock = jest.fn();  // <= ...the same mocks...
  return {
    Rest: () => ({ getSomething: getSomethingMock }),
    Websocket: () => ({ onUpdate: onUpdateMock })
  }
},
{ virtual: true });  // <= (use virtual since "npm-module" doesn't exist)

class Component {
  private _rest: any;
  private _websocket: any;
  public events = new EventEmitter();
  constructor() {
    this._rest = new Api.Rest();
    this._websocket = new Api.Websocket();
    this._init();
  }

  private _init() {
    this._websocket.onUpdate((data) => {  // <= ...so that this onUpdate...
      this.events.emit('update', data);
    });
  }
}

test('Component', () => {
  const component = new Component();
  const listener = jest.fn();
  component.events.on('update', listener);
  const onUpdate = new Api.Websocket().onUpdate;  // <= ...is the same as this one
  const onUpdateArrowFunction = onUpdate.mock.calls[0][0];  // <= get the arrow function passed to it
  onUpdateArrowFunction('mock data');  // <= now call the function
  expect(listener).toHaveBeenCalledWith('mock data');  // Success!
});

详细信息

Jest接管require系统,并允许您指定需要模块时要返回的内容(请注意,TypeScript import语句已编译为{{1} })。

模拟模块的一种方法是通过在require上创建一个包含模拟的文件来创建manual mock

另一种方法(如上所示)是使用jest.mock并将其传递给模块工厂函数。

在测试期间__mocks__/npm-module.ts每次需要模块时,都会返回模拟的模块。

请注意,上面的示例始终为JestgetSomething返回相同的模拟,因此可以在测试过程中检索这些模拟函数。

还请注意使用mockFn.mock.calls来检索此箭头功能:

onUpdate

...将其传递到(data) => { this.events.emit('update', data); } 。一旦检索到它,就可以直接调用它,从而按预期触发侦听器。