javascript - 如何在异步等待操作中测试 catch 语句

标签 javascript unit-testing react-redux jestjs

问题

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

Action

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: []
        });
    }
};

Action 测试

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);
})

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

但是当然,您仍然可以针对 dispatch 调用进行断言。要点:不要模拟 __mocks__ 自动模拟中返回的结果,而是在对等基础上进行。

关于javascript - 如何在异步等待操作中测试 catch 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57297920/

相关文章:

java - 在 Spring Web 应用程序中运行 JUnit 测试时指定 Maven 配置文件

java - Getmethod Mokito java 模拟

jquery - AngularJS - 带有 jquery 函数的单元测试指令

javascript - react-redux - ReferenceError : g is not defined

javascript - 在 redux 中创建选择器不起作用

javascript - 是否有一种设计模式的功能类似于观察者与装饰者的混合?

.net - 寻找通过纯​​ JavaScript 客户端访问的 .Net 服务的可下载演示,而不依赖 IIS 来提供服务

javascript - React 路由器显示没有匹配的路由器

javascript - Node.js module.exports 多个类

javascript - 使用 HTML、CSS 和 JavaScript 增加圆弧效果