【问题标题】:get new Instance for function each test为每个测试获取新的功能实例
【发布时间】:2021-10-02 19:59:21
【问题描述】:

我在一个文件中有一些测试,

我用一些案例检查了我的减速器

我的代码是这样的

my code

import axiosInstance from '~/utils/network';
const fetcher = axiosInstance();


const fetchMiddleware = () => {
  switch (type) {

     case 'LOGOUT':{
      try {
          await fetcher.get(API.GET.LOGOUT_OPERATION);

          dispatch({ type: 'LOGOUT_SUCCESS' });
        } catch (err) {
          dispatch({ type: 'LOGOUT_FAIL' });
        }
      });
     }
   }
}

my test


import axiosInstance from '../../src/utils/network';

import configureStore from 'redux-mock-store';

const middlewares = [fetchMiddleware, thunk];
const mockStore = configureStore(middlewares);
const store = mockStore(getInitialReducerState());


jest.mock('../../src/utils/network', () => {
  const axiosInstance = jest.fn().mockImplementation(() => {
    return {
      get: jest.fn().mockImplementation(() => {
        return {
          headers: {},
        };
      }),
    };
  }) as any;
  axiosInstance.configure = jest.fn();
  return axiosInstance;
});


describe('test LOGOUT', () => {
  beforeEach(() => {
    store.clearActions();
  });

  it('should test be success', async () => {
    await store.dispatch({
      type: 'LOGOUT',
      payload: { userName: 'testUserName' },
    });

    expect(store.getActions()).toContainEqual({
      type: 'LOGOUT_SUCCESS',
    });
  });

  it('should test be fail', async () => {
    (axiosInstance as jest.Mock).mockImplementation(() => {
      return {
        get: jest.fn().mockImplementation(() => {
          throw new Error(' ');
        }),
      };
    });
    await store.dispatch({
      type: 'LOGOUT',
      payload: { userName: 'testUserName' },
    });

    expect(store.getActions()).toContainEqual({
      type: 'LOGOUT_FAIL',
    });
  });
});

我想测试两个场景:成功和失败,

我模拟了axiosInstance 函数。

但即使我在第二个测试中覆盖了模拟,我也得到了第一个模拟,因为我的代码只加载了一次 axiosInstance

我能做什么?

【问题讨论】:

  • 在评论和答案之间来回切换。确定这绝对是评论。如果您还没有,我强烈建议您使用moxios。减少您自己需要维护的手动模拟代码。好的文档,设置应该很容易。
  • fetchMiddleware是如何使用的?
  • @RazLuvaton 更新了我的代码

标签: javascript reactjs unit-testing testing jestjs


【解决方案1】:

您需要使用jest.isolateModules


假设我们有 2 个文件:

  1. ./lib.js - 这是你的~/utils/network
  2. ./repro.js - 这是你的测试代码文件

./lib.js:

export default function lib() {
  return () => 10;
}

./repro.js:

import lib from './lib';
const fnInstance = lib();

export const fn = () => {
  return fnInstance();
};

还有./repro.test.js

function getRepro(libMock) {
  let repro;

  // Must use isolateModules because we need to require a new module everytime
  jest.isolateModules(() => {
    jest.mock('./lib', () => {
      return {
        default: libMock,
      };
    });

    repro = require('./repro');
  });

  // If for some reason in the future the behavior will change and this assertion will fail
  // We can do a workaround by returning a Promise and the `resolve` callback will be called with the Component in the `isolateModules` function
  // Or we can also put the whole test function inside the `isolateModules` (less preferred)
  expect(repro).toBeDefined();

  return repro;
}

describe('', () => {
  it('should return 1', () => {
    const { fn } = getRepro(function lib() {
      return () => 1
    });
    expect(fn()).toEqual(1);
  });

  it('should return 2', () => {
    const { fn } = getRepro(function lib() {
      return () => 2
    });

    expect(fn()).toEqual(2);
  });
});

【讨论】:

  • isolateModules 在这里太过分了。该模块不需要重新评估。
  • 我想听一个替代方案
  • 模拟的 axiosInstance 应该返回一个可以动态更改实现的间谍对象。当导入的值是标量或产生副作用时,需要使用isolateModules。
【解决方案2】:

最好使用现有的库来模拟 Axios,它可以避免样板代码和模拟实现中的潜在错误; moxios 已经被推荐了。

每次测试都模拟 axiosInstance 很不方便,因为它已经在导入测试模块时被调用,所以这需要每次测试重新导入它;另一个答案解释了它是如何使用jest.isolateModules 完成的。

由于axiosInstance 只被评估一次并且应该返回模拟对象,因此每次测试模拟一次然后更改实现很方便:

jest.mock('~/utils/network', () => {
  const axiosMock = { get: jest.fn(), ... };
  return {
    axiosInstance: () => axiosMock;
  };
});

const axiosMock = axiosInstance();

...

(axiosMock.get axiosInstance as jest.Mock).mockImplementation(() => {
  throw new Error(' ');
});

await store.dispatch(...);

这需要在beforeEach 中使用jest.restoreAllMocks 或类似的Jest 配置选项以避免测试交叉污染。

请注意,Axios 不会抛出错误而是返回被拒绝的 Promise,这可能会影响测试结果,请参阅有关库的好处的说明。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-01
    • 2012-06-07
    • 1970-01-01
    • 1970-01-01
    • 2011-09-27
    相关资源
    最近更新 更多