【问题标题】:What is the best way to mock in Jest Unit Test this package?在 Jest Unit Test 这个包中模拟的最佳方法是什么?
【发布时间】:2021-03-08 13:47:35
【问题描述】:

美好的一天!我正在使用 Amplitude 是一项用于监视您的操作等的服务。但是回到我的问题,此时我正在尝试模拟这个模块“amplitude-js”来进行测试,但我认为我在嘲笑一个不好的方式..所以如果有人可以帮助我以正确的方式做到这一点,我将不胜感激。所以首先从我想要测试的功能开始是这个:

export const signIn = (): ThunkAction<
  void,
  RootState,
  null,
  FluxStandardAction
> => {
  return async (dispatch, getState) => {
    const { username, password } = getState().Authentication;
    amplitude.getInstance().logEvent('LOGIN_SIGN_IN_REQUEST'); <=== This
    dispatch(signInRequest() as FluxStandardAction<string, any>);

    try {
      const response = await axios.post(`${API}/users/login`, {
        username,
        password,
      });
      const { data } = response;
      amplitude.getInstance().logEvent('LOGIN_SIGN_IN_SUCCESS', data); <=== This as well
      dispatch(signInSuccess(data.token) as FluxStandardAction<string, any>);
    } catch (err) {
      Sentry.captureException(err);
      dispatch(signInFailure(err) as FluxStandardAction<string, any>);
    }
  };
};

正如您所看到的,我使用 redux 来调度操作,我在没有尝试模拟 Amplitude 的情况下对我的函数进行了测试,并且测试非常完美。我将分享我的测试代码,你可以看到我有什么。记住我只想测试振幅,其他值我不在乎!!

测试:


jest.mock('axios');
jest.mock('amplitude-js');

import axios from 'axios';
import amplitude from 'amplitude-js';

import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { API } from '../../../src/Config';
import * as actions from '../../../src/redux/actions/authentication/authentication';

const middleware = [thunk];
const mockStore = configureStore(middleware);
const store = mockStore({});
const mockT = jest.fn().mockReturnValue('LOGIN_SIGN_IN_REQUEST');

describe('Authentication async action', () => {
  describe("'onLogin' actions", () => {
    beforeEach(() => {
      store.clearActions();
    });
    it('creates LOGIN_SIGN_IN_SUCCESS on successful authentication', async () => {
      const token = 'token';

      (axios.post as jest.Mock).mockReset();
      (axios.post as jest.Mock).mockResolvedValue({
        data: {
          token,
        },
      });

      (amplitude.getInstance as any).mockReset();

      const expectedActions = [
        {
          type: actions.LOGIN_SIGN_IN_REQUEST,
        },
        {
          type: actions.LOGIN_SIGN_IN_SUCCESS,
          payload: token,
        },
      ];
      const store = mockStore({
        Authentication: {
          username: 'username',
          password: 'password',
        },
      });

      await store.dispatch(actions.signIn() as any);
      expect(amplitude.getInstance().logEvent('LOGIN_SIGN_IN_REQUEST'));
      expect(store.getActions()).toEqual(expectedActions);
      expect(axios.post).toHaveBeenCalledWith(`${API}/users/login`, {
        username: 'username',
        password: 'password',
      });
    });

所以当我在 Jest 中运行测试时,我收到了这个错误:


  ● Authentication async action › 'onLogin' actions › creates LOGIN_SIGN_IN_SUCCESS on successful authentication

    TypeError: Cannot read property 'logEvent' of undefined

      103 |   return async (dispatch, getState) => {
      104 |     const { username, password } = getState().Authentication;
    > 105 |     amplitude.getInstance().logEvent('LOGIN_SIGN_IN_REQUEST');
          |     ^
      106 |     dispatch(signInRequest() as FluxStandardAction<string, any>);
      107 | 
      108 |     try {

      at src/redux/actions/authentication/authentication.ts:105:5

如果我这样称呼:

describe('Authentication async action', () => {
  describe("'onLogin' actions", () => {
    beforeEach(() => {
      store.clearActions();
    });
    it('creates LOGIN_SIGN_IN_SUCCESS on successful authentication', async () => {
      const token = 'token';

      (axios.post as jest.Mock).mockReset();
      (axios.post as jest.Mock).mockResolvedValue({
        data: {
          token,
        },
      });

      (amplitude.getInstance() as any).mockReset(); <=== i call getsIstance()

      const expectedActions = [
        {
          type: actions.LOGIN_SIGN_IN_REQUEST,
        },
        {
          type: actions.LOGIN_SIGN_IN_SUCCESS,
          payload: token,
        },
      ];
      const store = mockStore({
        Authentication: {
          username: 'username',
          password: 'password',
        },
      });

      await store.dispatch(actions.signIn() as any);
      expect(amplitude.getInstance().logEvent('LOGIN_SIGN_IN_REQUEST'));
      expect(store.getActions()).toEqual(expectedActions);
      expect(axios.post).toHaveBeenCalledWith(`${API}/users/login`, {
        username: 'username',
        password: 'password',
      });
    });

现在我收到了这个错误:


    TypeError: Cannot read property 'mockReset' of undefined

      36 |       });
      37 | 
    > 38 |       (amplitude.getInstance() as any).mockReset();
         |       ^
      39 | 
      40 |       const expectedActions = [
      41 |         {

      at Object.<anonymous> (test/redux/Authentication/Authentication.action.async.test.ts:38:7)

很烦人..

也许是很容易模拟的东西..但我没有太多的测试经验!

【问题讨论】:

    标签: javascript reactjs unit-testing redux jestjs


    【解决方案1】:

    我去

    beforeEach(() => {
      window.amplitude = {
        getInstance: jest.fn(() => ({ logEvent: jest.fn() })),
      };
    });
    

    我们会看看它是否通过了代码审查。您可能还需要 setUserProperties 等,具体取决于您正在渲染/测试的组件以及它们的作用

    可能还需要afterEach 中的某些内容来清理它,不确定。如果有人能插话就好了

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-01
      • 2011-12-04
      • 2010-11-20
      • 2020-02-03
      • 1970-01-01
      • 2012-01-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多