为什么开玩笑不叫我的模拟实现

时间:2020-10-30 05:04:20

标签: javascript unit-testing jestjs mocking

我已经阅读了有关Jest的每一个SO问题和文档的每一个片段,但是我仍然不知道为什么Jest似乎根本不使用我的模拟实现。

  1. 我正在测试的代码确实按预期工作。
  2. 我正在尝试模拟XMLHttpRequest。
  3. 我想在多个单元测试中共享我的模拟。

我不确定是否应遵循模拟ES6类的说明。 XMLHttpRequest是窗口对象的方法,而不是真正的类,而类只是返回对象的函数,因此XMLHttpRequest毕竟是类。

由于我想共享我的模拟,所以我认为它适合手动模拟的模式,除了XMLHttpRequest不是模块,而且看起来手动模拟仅适用于模块。

这就是我写的模拟:

function mainMock() {
  let readyState = 4;
  let status = 200;
  let statusText = 'OK';
  let responseText = 'mocked data';
  let response = {};
  let error = null;

  const open = jest.fn();
  const onreadystatechange = jest.fn();
  const send = jest.fn(function send() {
    if (error) throw error;
    this.onreadystatechange();
  });

  const addEventListener = jest.fn(function addEventListener(e, c) {
    this.onreadystatechange = c;
  });

  function setStatus(newStatus = 200, newStatusText = 'OK', newReadyState = 4) {
    status = newStatus;
    statusText = newStatusText;
    readyState = newReadyState;
  }

  function setResponseText(newResponseText) {
    responseText = newResponseText;
    response = {};
  }

  function setResponse(newResponse) {
    responseText = JSON.stringify(newResponse);
    response = newResponse;
  }

  function setError(newError) {
    error = newError;
  }

  function cleanUp() {
    if (window.XMLHttpRequest) {
      delete window.XMLHttpRequest;
    }
  }

  // mock constructor that will replace window XMLHttpRequest
  function mockConstructor() {
    return {
      readyState,
      status,
      statusText,
      responseText,
      response,
      open,
      onreadystatechange,
      addEventListener,
      send,
    };
  }

  // override/define XMLHttpRequest
  window.XMLHttpRequest = mockConstructor;

  return {
    open,
    onreadystatechange,
    addEventListener,
    cleanUp,
    setStatus,
    setResponseText,
    setResponse,
    setError,
    send,
  };
}

export default mainMock;

这是我的(缩写)单元测试

import XMLHttpRequestMock from '~mocks/XMLHttpRequestMock';
import { Service } from './Service';

let mockXMLHttpRequest;
beforeEach(() => {
  mockXMLHttpRequest = XMLHttpRequestMock();
});

afterEach(() => {
  mockXMLHttpRequest.cleanUp();
});

describe('Service', () => {
  it('should-ping', async () => {
    mockXMLHttpRequest.setResponse({
      meta: { version: 99 },
      data: {},
    });

    const service = new Service();
    const meta = await service.ping();
    expect(mockXMLHttpRequest.open).toHaveBeenCalled();
    expect(mockXMLHttpRequest.send).toHaveBeenCalled();
    expect(meta.version).toEqual(99);
    expect(meta.status).toEqual(200);
  });
});

我正在测试的类肯定会调用opensend方法,因为它实际上可以工作并从服务器中提取数据,但是expect(mockXMLHttpRequest.open)失败了,因此所有其他expect个电话(如果我放在第一位)。看来Jest根本根本没有使用该模拟。

我从这里去哪里?

为使图片更加完整,这是我正在测试的课程的简化版本。

import configVars from '~config/configVars';
import 'regenerator-runtime/runtime.js';

export class Service {
  constructor(logger) {
    this.logger = logger || console;
  }

  _getJson(request) {
    const _this = this;
    return new Promise(function(resolve, reject) {
      var xhttp = new XMLHttpRequest();
      xhttp.responseType = request.responseType || 'json';
      xhttp.onreadystatechange = function() {
        if (xhttp.readyState === XMLHttpRequest.DONE) {
          if (this.status >= 200 && this.status < 300) {
            resolve(this);
          } else {
            let e = {
              status: this.status,
              statusText: this.statusText,
            };
            reject(e);
          }
        }
      };
      let url = configVars.service.url + request.url;
      xhttp.open('GET', url, true);
      xhttp.setRequestHeader('Accept', request.accept || 'application/json');
      try {
        xhttp.send();
      } catch (e) {
        reject(e);
      }
    });
  }

  async ping() {
    try {
      let xhttp = await this._getJson({ url: 'ping' });
      let meta = xhttp.response.meta;
      meta.status = xhttp.status;
      meta.statusText = xhttp.statusText;
      return meta;
    } catch (e) {
      e.messages = e.messages || [];
      e.messages.push('Ping of service failed');
      return e;
    }
  }
}

export default Service;

1 个答案:

答案 0 :(得分:0)

经过大量的摸索并试图弄清楚如何使VS Code调试器通过Jest测试,我终于将其归结为一个非常简单的东西。

我没有模拟setRequestHeader,这导致我的类在调用send方法之前引发了异常。