问题
我有一个等待 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/