如何测试返回异步函数的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
相关产品推荐
相关产品推荐

