模拟多层深度的 API 调用

时间:2021-07-12 21:23:16

标签: javascript unit-testing jestjs

所以我尝试使用 Jest 模拟嵌套在其他辅助函数中的辅助函数。

我真正要测试的函数的基本结构是这样的

import matrixClient from '@mapbox/mapbox-sdk/services/matrix';

// I want to test this function which uses several other helpers
export const getOrderEstimate = async (start, end) => {
  // other non-delivery estimate stuff
  const deliveryEstimate = await getDeliveryEstimate(start, end);

  return {
    ...otherStuff
    delivery: deliveryEstimate 
  }
}

const getDeliveryEstimate = async (start, end) => {
  try {
    return await functionThatWrapsMapBox(start, end);
  } catch(error) {
    // return error
  }
}

const functionThatWrapsMapBox = async (start, end) => {
  return matrixClient({ accessToken: MAPBOX_TOKEN })
    .getMatrix({
      points: [{ coordinates: start }, { coordinates: end }],
      profile: `driving-traffic`,
    })
    .send();
}

在我的测试文件中,我试图做这样的事情,

import * as helpers from './order-estimates';

describe('order estimates', () => {
  test('delivery estimates should never be null', () => {
    const mockMapBox = jest.spyOn(helpers, 'functionThatWrapsMapBox');
    mockMapBox.mockReturnValue(() => ...mockedReturn))
    // this function always uses the real implementation of functionThatWrapsMapBox
    const orderEstimates = helpers.getOrderEstimate(startAddress, endAddress);
    expect(orderEstimates.delivery).not.toBeNull();
  });
});

我已经尝试了几种使用 jest.mock 的手动模拟技术,我只能让模拟实现触发如果我直接在我的测试文件中调用它,这并不是我真正想要的.我认为 jest.spyOn 方法更合适,但还没有运气。

1 个答案:

答案 0 :(得分:0)

我提出的解决方案确实反映了文档 found here。本质上,我将地图框客户端拉到它自己的模块中,该模块与此帮助模块相邻。然后我在 __mocks__ 目录中创建了一个模拟实现。然后在我的测试中,它就像在文件顶部放置 jest.mock('./mapbox'); 一样简单,并且使用了模拟实现。我现在也可以访问更细粒度的控件。

总结

首先,我将 mapbox 客户端提取到它自己的文件中。

import functionThatWrapsMapBox from './mapbox';

// I want to test this function which uses several other helpers
export const getOrderEstimate = async (start, end) => {
  // other non-delivery estimate stuff
  const deliveryEstimate = await getDeliveryEstimate(start, end);

  return {
    ...otherStuff
    delivery: deliveryEstimate 
  }
}

const getDeliveryEstimate = async (start, end) => {
  try {
    return await functionThatWrapsMapBox(start, end);
  } catch(error) {
    // return error
  }
}

所以,mapbox.js

import matrixClient from '@mapbox/mapbox-sdk/services/matrix';

const functionThatWrapsMapBox = async (start, end) => {
  return matrixClient({ accessToken: MAPBOX_TOKEN })
    .getMatrix({
      points: [{ coordinates: start }, { coordinates: end }],
      profile: `driving-traffic`,
    })
    .send();
}

default export functionThatWrapsMapBox;

并在__mocks__/mapbox.js中:

const functionThatWrapsMapBox = async (origin, destination) => {
  return new Promise((resolve, reject) => {
    process.nextTick(() => {
      if (origin && destination) {
        resolve({
          body: {
            durations: [
              [0.0, 135.4],
              [131.5, 0.0],
            ],
          },
        });
      } else {
        reject(new Error('Please provide and origin and a destination'));
      }
    });
  });
};

export default functionThatWrapsMapBox;

最后在我的测试中:

import { getOrderEstimate } from './order-estimates';

jest.mock('./mapbox');

describe('order estimates', () => {
  test('delivery estimates should never be null', () => {
    // this function uses the mock implementation of functionThatWrapsMapBox
    const orderEstimates = getOrderEstimate(startAddress, endAddress);
    expect(orderEstimates.delivery).not.toBeNull();
  });
});

向@jonrsharpe 致以崇高的敬意,感谢他们说明了正确的做法!