如何在玩笑中测试从构造函数调用然后调用其他异步函数的 init() 函数

How to test an init() function in jest that is called from constructor and then calls other async functions

我在javascript中有以下代码:

class SampleClass {
  constructor(param1) {
    this.param1 = param1;
    this.init();
  }
  async init() {
    await this.getData();
    this.loadIframe();
  }
  async getData() {
    const response = fetch(url);
    const data = response.json();
    //set the response to class variable
    this.param2 = data;
  }
  loadIframe() {
    //some logic to load iframe.
  }
}

使用 jest 进行测试的最佳方法是什么?

目前我正在通过模拟 init() 函数来测试构造函数逻辑。

但是我还必须测试 getData() 函数。测试 getData() 方法的方法应该是什么。

我尝试通过不模拟 init() 函数并使用异步测试来测试 getData() 函数,但我不确定 在测试中在哪里使用 await 因为该函数是嵌套的,并且是从构造函数调用的 init 中调用的。

it('should fetch data', async()=>{
   //some logic  
})

您可以使用 jest.spyOn(object, methodName) 来模拟 SampleClass 的方法。我的测试环境是 node,所以我在 global 对象上模拟 fetch 方法。如果您的测试环境是 browserfetch 方法在 window 对象上。

例如

sampleClass.js:

class SampleClass {
  constructor(param1) {
    this.param1 = param1;
    this.init();
  }
  async init() {
    await this.getData();
    this.loadIframe();
  }
  async getData() {
    const url = 'https://whosebug.com/';
    const response = fetch(url);
    const data = response.json();
    this.param2 = data;
  }
  loadIframe() {}
}

export { SampleClass };

sampleClass.test.js:

import { SampleClass } from './sampleClass';

describe('60146073', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  describe('#constructor', () => {
    it('should consturt', () => {
      jest.spyOn(SampleClass.prototype, 'constructor');
      jest.spyOn(SampleClass.prototype, 'init').mockReturnValueOnce();
      const instance = new SampleClass('param1');
      expect(instance.param1).toBe('param1');
      expect(instance.init).toBeCalledTimes(1);
    });
  });
  describe('#init', () => {
    it('should init', async () => {
      jest.spyOn(SampleClass.prototype, 'getData').mockResolvedValueOnce();
      jest.spyOn(SampleClass.prototype, 'loadIframe').mockReturnValueOnce();
      jest.spyOn(SampleClass.prototype, 'init').mockReturnValueOnce();
      const instance = new SampleClass();
      await instance.init();
      expect(instance.getData).toBeCalledTimes(1);
      expect(instance.loadIframe).toBeCalledTimes(1);
    });
  });

  describe('#getData', () => {
    it('should fetch data', async () => {
      const mResponse = { json: jest.fn().mockReturnValueOnce({}) };
      global.fetch = jest.fn().mockResolvedValueOnce(mResponse);
      jest.spyOn(SampleClass.prototype, 'init').mockReturnValueOnce();
      const instance = new SampleClass();
      await instance.getData();
      expect(global.fetch).toBeCalledWith('https://whosebug.com/');
      expect(mResponse.json).toBeCalledTimes(1);
    });
  });
});

100% 覆盖率的单元测试结果:

 PASS  Whosebug/60146073/sampleClass.test.js
  60146073
    #constructor
      ✓ should consturt (3ms)
    #init
      ✓ should init (2ms)
    #getData
      ✓ should fetch data (2ms)

----------------|---------|----------|---------|---------|-------------------
File            | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------------|---------|----------|---------|---------|-------------------
All files       |     100 |      100 |      80 |     100 |                   
 sampleClass.js |     100 |      100 |      80 |     100 |                   
----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        4.137s, estimated 5s

源代码:https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/Whosebug/60146073