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

如何测试返回异步函数的React自定义Hook useListAllThreads?

测试React自定义Hook useListAllThreads的单元测试方案

问题描述

我需要测试下方提供的React自定义Hook,但找不到可参考的示例或教程来测试这类Hook:

export const useListAllThreads = () => {
    const {miraklListAllThreads} = useM11()
    const {getTokenWhenReady} = useAccessToken()

    return {
        /**
         * List all threads - Mirakl m11
         * @param {string} customerID - Customer id to include in result
         * @returns {Object} result - The result object with data, success, and msg
         */
        async getMiraklListAllThreads(customerID) {
            const token = await getTokenWhenReady()
            let result = {
                data: null,
                success: false,
                msg: null
            }

            try {
                const params = {
                    customer_id: customerID
                }

                const response = await miraklListAllThreads(params, token)
                if (!response || response.success == false) {
                    result.msg = 'Error getting Mirakl M11. Please check your configuration.'
                    result.success = false
                } else {
                    result.data = response.data
                    result.success = true
                }
            } catch (error) {
                result.msg = error.message
                result.success = false
            }

            return result
        }
    }
}

我曾尝试mock miraklListAllThreads和getTokenWhenReady,但仍无法实现对Hook功能的测试,请问能否有人帮我为该Hook编写单元测试?


解决方案

我们可以使用@testing-library/react-hooks配合Jest来完成测试,核心是正确mock依赖的两个自定义Hook,覆盖成功、接口失败、异常三种核心场景。

步骤1:安装依赖

确保项目已安装必要的测试包:

npm install --save-dev @testing-library/react-hooks jest @testing-library/react

步骤2:编写单元测试代码

import { renderHook } from '@testing-library/react-hooks';
import { useListAllThreads } from './path-to-your-hook';

// Mock 依赖的自定义Hook
jest.mock('./path-to-useM11', () => ({
  useM11: () => ({
    miraklListAllThreads: jest.fn()
  })
}));

jest.mock('./path-to-useAccessToken', () => ({
  useAccessToken: () => ({
    getTokenWhenReady: jest.fn().mockResolvedValue('mock-token-123')
  })
}));

describe('useListAllThreads', () => {
  const mockCustomerID = 'test-customer-123';
  
  beforeEach(() => {
    // 清除所有mock调用记录,避免测试用例相互干扰
    jest.clearAllMocks();
  });

  test('getMiraklListAllThreads 成功获取数据', async () => {
    // 模拟mirakl接口返回成功响应
    const mockResponse = {
      success: true,
      data: [{ id: 'thread-1', title: 'Test Thread' }]
    };
    const { miraklListAllThreads } = require('./path-to-useM11').useM11();
    miraklListAllThreads.mockResolvedValue(mockResponse);

    // 渲染Hook并调用目标方法
    const { result } = renderHook(() => useListAllThreads());
    const response = await result.current.getMiraklListAllThreads(mockCustomerID);

    // 断言结果正确性
    expect(response.success).toBe(true);
    expect(response.data).toEqual(mockResponse.data);
    expect(response.msg).toBe(null);
    
    // 断言依赖方法的调用参数
    expect(miraklListAllThreads).toHaveBeenCalledWith(
      { customer_id: mockCustomerID },
      'mock-token-123'
    );
    expect(require('./path-to-useAccessToken').useAccessToken().getTokenWhenReady).toHaveBeenCalled();
  });

  test('getMiraklListAllThreads 接口返回失败时返回预设错误信息', async () => {
    // 模拟mirakl接口返回失败响应
    const mockResponse = { success: false };
    const { miraklListAllThreads } = require('./path-to-useM11').useM11();
    miraklListAllThreads.mockResolvedValue(mockResponse);

    const { result } = renderHook(() => useListAllThreads());
    const response = await result.current.getMiraklListAllThreads(mockCustomerID);

    expect(response.success).toBe(false);
    expect(response.msg).toBe('Error getting Mirakl M11. Please check your configuration.');
    expect(response.data).toBe(null);
  });

  test('getMiraklListAllThreads 接口抛出异常时捕获错误信息', async () => {
    // 模拟mirakl接口抛出异常
    const mockError = new Error('Network connection failed');
    const { miraklListAllThreads } = require('./path-to-useM11').useM11();
    miraklListAllThreads.mockRejectedValue(mockError);

    const { result } = renderHook(() => useListAllThreads());
    const response = await result.current.getMiraklListAllThreads(mockCustomerID);

    expect(response.success).toBe(false);
    expect(response.msg).toBe(mockError.message);
    expect(response.data).toBe(null);
  });
});

注意事项

  • 替换代码中的./path-to-your-hook、./path-to-useM11、./path-to-useAccessToken为项目中实际的文件路径
  • 可根据需求扩展测试场景,比如getTokenWhenReady抛出异常的情况
  • renderHook是@testing-library/react-hooks提供的专门用于测试自定义Hook的方法,能正确处理Hook的生命周期

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 14:20:31