You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试柯里化的Axios Redux Action是否被调用?

测试柯里化Redux Action的Jest模拟方案

问题场景

我有一个带柯里化dispatch的Redux Action,通过Axios发起请求,在React Native组件中用自定义hook调用该Action。编写测试代码时,mockDispatch的调用次数始终不符合预期,尝试多种模拟方式均未解决,需要明确如何用Jest正确模拟柯里化函数完成测试。

相关代码示例

1. Redux Action代码(./src/store/Auth/auth.action.ts)

import { Dispatch } from 'redux';
import axios from 'axios';

export default {
    getUsersData: () => (dispatch: Dispatch) => {
        return axios.get('https://jsonplaceholder.typicode.com/users').then((result) => {
            dispatch({
                type: 'SET_USERS',
                payload: result
            });

            return result;
        })
            .catch((e) => {
                console.error(e);
            });
    },
}

2. React Native组件代码(./src/screens/Testing/index.tsx)

import React, { useCallback } from 'react';
import { View, Button } from 'react-native';
import { useDispatch } from 'react-redux';

import Action from '../../store/Auth/auth.action';

const useAppDispatch = (action: any) => {
    const dispatch = useDispatch();

    return useCallback((param?: any, callback?: any) => dispatch(action(param, callback)), [dispatch, action]);
};

const Testing = () => {
    const getUsersDataAction = useAppDispatch(Action.getUsersData);

    return (
        <View>
            <Button
                title='hit me'
                testID='hit_me_id'
                onPress={ () => getUsersDataAction() }
            />
        </View>
    );
};

export default Testing;

3. 当前测试代码(action.test.js)

import * as React from 'react';
import * as ReactRedux from 'react-redux';
import axios from 'axios';
import { render, fireEvent, waitFor } from '@testing-library/react-native';

import { Testing } from '../../src/screens';

describe('Get users data', () => {
    it('should return correct payload', async () => {
        const mockDispatch = jest.fn();

        jest.spyOn(ReactRedux, 'useDispatch').mockReturnValue(mockDispatch);

        axios.get.mockResolvedValue({});

        const screen = render(
            <Testing />
        );

        await waitFor(() => {
            expect(screen.getByTestId('hit_me_id')).toBeTruthy();
        });

        await waitFor(() => {
            fireEvent.press(screen.getByTestId('hit_me_id'));
        });

        expect(mockDispatch).toHaveBeenCalledTimes(1);
        expect(axios.get).toHaveBeenCalledWith('https://jsonplaceholder.typicode.com/users');
    });
});

尝试过的无效模拟方式

const mockDispatch = () => jest.fn();
const mockDispatch = jest.fn(() => () => null);

jest.spyOn(ReactRedux, 'useDispatch').mockReturnValue(mockDispatch());
jest.spyOn(ReactRedux, 'useDispatch').mockReturnValue(() => mockDispatch());

解决方案

问题核心在于Redux的dispatch本身支持传入函数(Thunk),会自动执行该函数并将自身作为参数传入,而之前的mockDispatch没有模拟这个行为,导致柯里化的Action函数未被执行,流程中断。

修正后的测试代码

import * as React from 'react';
import * as ReactRedux from 'react-redux';
import axios from 'axios';
import { render, fireEvent, waitFor } from '@testing-library/react-native';

import Testing from '../../src/screens/Testing';

describe('Get users data', () => {
    it('should return correct payload and dispatch action', async () => {
        // 模拟Redux dispatch的核心行为:执行传入的柯里化Action函数
        const mockDispatch = jest.fn((actionOrFn) => {
            if (typeof actionOrFn === 'function') {
                return actionOrFn(mockDispatch);
            }
            return actionOrFn;
        });

        jest.spyOn(ReactRedux, 'useDispatch').mockReturnValue(mockDispatch);
        
        // 模拟Axios返回的测试数据
        const mockUsers = [{id: 1, name: 'Test User'}];
        axios.get.mockResolvedValue(mockUsers);

        const screen = render(<Testing />);

        // 触发按钮点击
        fireEvent.press(screen.getByTestId('hit_me_id'));

        // 等待异步流程完成后验证
        await waitFor(() => {
            // 验证Axios请求地址正确
            expect(axios.get).toHaveBeenCalledWith('https://jsonplaceholder.typicode.com/users');
            
            // 验证dispatch被调用两次:一次传入柯里化函数,一次分发SET_USERS Action
            expect(mockDispatch).toHaveBeenCalledTimes(2);
            
            // 验证最终分发的Action内容正确
            expect(mockDispatch).toHaveBeenCalledWith({
                type: 'SET_USERS',
                payload: mockUsers
            });
        });
    });
});

关键说明

  • 修正后的mockDispatch会判断传入的参数类型:如果是函数(即柯里化的Action),就执行该函数并把自身作为参数传入,完全模拟Redux原生dispatch的行为。
  • 此时mockDispatch会被调用两次:第一次是组件中调用dispatch(action(param, callback)),传入的是getUsersData()返回的函数;第二次是在该函数内部调用dispatch({type: 'SET_USERS', ...}),传入的是Action对象。

内容的提问来源于stack exchange,提问作者fadly kayo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 12:59:15