繁体   English   中英

如何在 async await Action 中测试 catch 语句

[英]How to test catch statement in async await Action

问题

我有一个等待 API 函数的操作。 使用我的模拟 API 可以轻松测试 try 中的快乐路径。 但是,不确定测试和覆盖.catch的最佳方法。

行动

import {getRoles} from '../shared/services/api';

export const Actions = {
    SET_ROLES: 'SET_ROLES'
};

export const fetchRoles = () => async dispatch => {
    try {
        const response = await getRoles();
        const roles = response.data;

        dispatch({
            type: Actions.SET_ROLES,
            roles
        });
    } catch (error) {
        dispatch({
            type: Actions.SET_ROLES,
            roles: []
        });
    }
};

动作测试

import {fetchRoles} from '../party-actions';
import rolesJson from '../../shared/services/__mocks__/roles.json';
jest.mock('../../shared/services/api');

describe('Roles Actions', () => {
    it('should set roles when getRoles() res returns', async () => {
        const mockDispatch = jest.fn();

        await fetchRoles()(mockDispatch);
        try {
            expect(mockDispatch).toHaveBeenCalledWith({
                type: 'SET_ROLES',
                roles: rolesJson
            });
        } catch (e) {
            // console.log('fetchRoles error: ', e)
        }
    });

    // Here is the problem test, how do we intentionally cause
    // getRoles() inside of fetchRoles() to throw an error?
    it('should return empty roles if error', async () => {
        const mockDispatch = jest.fn();

        await fetchRoles('throwError')(mockDispatch);

        expect(mockDispatch).toHaveBeenCalledWith({
            type: 'SET_ROLES',
            roles: []
        });
    });
});

模拟 API

import rolesJson from './roles.json';

export const getRoles = async test => {
    let mockGetRoles;

    if (test === 'throwError') {
        //   console.log('sad')
        mockGetRoles = () => {
            return Promise.reject({
                roles: []
            });
        };
    } else {
        // console.log('happy')
        mockGetRoles = () => {
            return Promise.resolve({
                roles: rolesJson
            });
        };
    }

    try {
        const roles = mockGetRoles();
        // console.log('api mocks roles', roles);
        return roles;
    } catch (err) {
        return 'the error';
    }
};

^ 以上您可以看到我尝试过的方法,它确实有效,但它要求我以适合测试的方式更改我的代码,而不是应用程序的实际逻辑。

例如,要通过此测试,我必须通过实际代码传入一个变量(请参阅x ):

export const fetchRoles = (x) => async dispatch => {
    try {
        const response = await getRoles(x);
        const roles = response.data;

我们如何强制模拟中的getRoles在我们的悲伤路径.catch测试中抛出错误?

您可以在每个测试的基础上模拟getRoles API:

// getRoles will be just jest.fn() stub
import {getRoles} from '../../shared/services/api'; 
import rolesJson from '../../shared/services/__mocks__/roles.json';

// without __mocks__/api.js it will mock each exported function as jest.fn();
jest.mock('../../shared/services/api'); 

it('sets something if loaded successfully', async ()=> {
  getRoles.mockReturnValue(Promise.resolve(rolesJson));
  dispatch(fetchRoles());
  await Promise.resolve(); // so mocked API Promise could resolve
  expect(someSelector(store)).toEqual(...);
});

it('sets something else on error', async () => {
  getRoles.mockReturnValue(Promise.reject(someErrorObject));
  dispatch(fetchRoles());
  await Promise.resolve();
  expect(someSelector(store)).toEqual(someErrornessState);
})

我还建议您在调用后专注于存储状态,而不是调度的操作列表。 为什么? 因为实际上我们并不关心在我们存储预期数据时按什么顺序分派了哪些操作,对吗?

但是可以肯定的是,您仍然可以对dispatch调用进行断言。 要点:不要模拟__mocks__ automocks 中返回的结果,而是在对等基础上这样做。

我通过在模拟 api 文件中添加一个名为mockGetRolesError的函数解决了测试并获得了.catch的行覆盖:

感谢@skyboyer 提出在模拟文件上使用方法的想法。

import {getRoles} from '../shared/services/api';

export const Actions = {
    SET_ROLES: 'SET_ROLES'
};

export const fetchRoles = () => async dispatch => {
    try {
        const response = await getRoles();
        const roles = response.data;
        // console.log('ACTION roles:', roles);

        dispatch({
            type: Actions.SET_ROLES,
            roles
        });
    } catch (error) {
        dispatch({
            type: Actions.SET_ROLES,
            roles: []
        });
    }
};

现在在对悲伤路径的测试中,我只需要调用mockGetRolesErrormockGetRolesError的 api 的内部状态设置为返回错误模式。

import {fetchRoles} from '../party-actions';
import rolesJson from '../../shared/services/__mocks__/roles.json';
import {mockGetRolesError} from '../../shared/services/api';
jest.mock('../../shared/services/api');

describe('Roles Actions', () => {
    it('should set roles when getRoles() res returns', async () => {
        const mockDispatch = jest.fn();

        try {
            await fetchRoles()(mockDispatch);
            expect(mockDispatch).toHaveBeenCalledWith({
                type: 'SET_ROLES',
                roles: rolesJson
            });
        } catch (e) {
            return e;
        }
    });

    it('should return empty roles if error', async () => {
        const mockDispatch = jest.fn();

        mockGetRolesError();
        await fetchRoles()(mockDispatch);

        expect(mockDispatch).toHaveBeenCalledWith({
            type: 'SET_ROLES',
            roles: []
        });
    });
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM