如何使用React Testing Library单元测试Redux Toolkit?求指导
Redux Toolkit 测试方案指导
关于测试范围的疑问
建议分开测试service层和slice层,同时补充组件集成测试:
- 单独测试service:聚焦API调用逻辑(URL构造、请求参数、响应处理),能快速定位API相关问题。
- 单独测试slice:聚焦状态更新逻辑(pending/fulfilled/rejected时的状态变化),确保状态流转符合预期。
- 集成测试:验证组件、Redux、API的整体交互,模拟真实用户场景,保障功能端到端可用。
一、Service层测试(my.service.test.ts)
核心是mock外部依赖,验证fetchBeginningHeadcount的API调用逻辑:
import { fetchBeginningHeadcount, allHeadcountApiPaths } from './my.service'; import { api } from '../path-to-your-api-module'; import { ApiUrlService } from '../path-to-api-url-service'; // Mock外部依赖 jest.mock('../path-to-your-api-module', () => ({ api: jest.fn() })); jest.mock('../path-to-api-url-service', () => ({ ApiUrlService: { getTDS: jest.fn(() => 'mock-tds-url') } })); describe('fetchBeginningHeadcount', () => { const mockParams = { versionId: 'v1', page: 0, size: 10 }; const mockResponse = { content: [], totalElements: 0, totalPages: 1 }; beforeEach(() => jest.clearAllMocks()); it('调用API时使用正确的方法和URL', async () => { (api as jest.Mock).mockResolvedValue({ data: mockResponse }); await fetchBeginningHeadcount(mockParams); const expectedUrl = `${ApiUrlService.getTDS()}/rpc/v1/version/${mockParams.versionId}/planned-headcount/view/with-relations?page=${mockParams.page}&size=${mockParams.size}`; expect(api).toHaveBeenCalledWith('GET', expectedUrl, {}); }); it('API调用成功时返回正确数据', async () => { (api as jest.Mock).mockResolvedValue({ data: mockResponse }); const result = await fetchBeginningHeadcount(mockParams); expect(result.payload).toEqual(mockResponse); expect(result.type).toBe('allHeadcount/fetchBeginningHeadcount/fulfilled'); }); it('API调用失败时返回错误信息', async () => { const mockError = new Error('API请求失败'); (api as jest.Mock).mockRejectedValue(mockError); const result = await fetchBeginningHeadcount(mockParams); expect(result.error.message).toBe('API请求失败'); expect(result.type).toBe('allHeadcount/fetchBeginningHeadcount/rejected'); }); });
二、Slice层测试(my.slice.test.ts)
直接模拟action,验证状态更新逻辑,无需依赖API:
import allHeadcountReducer, { initialState } from './my.slice'; import { fetchBeginningHeadcount } from './my.service'; describe('allHeadcountSlice', () => { const mockData = [{ id: 1, name: '测试人员' }]; const mockPayload = { content: mockData, totalElements: 1, totalPages: 1 }; it('pending状态下设置loading为true', () => { const nextState = allHeadcountReducer( initialState, fetchBeginningHeadcount.pending('req-id') ); expect(nextState.beginningHeadcount.loading).toBe(true); expect(nextState.beginningHeadcount.error).toBeNull(); }); it('fulfilled状态下更新数据', () => { const nextState = allHeadcountReducer( initialState, fetchBeginningHeadcount.fulfilled(mockPayload, 'req-id') ); expect(nextState.beginningHeadcount.loading).toBe(false); expect(nextState.beginningHeadcount.data).toEqual(mockData); expect(nextState.beginningHeadcount.total).toBe(1); }); it('rejected状态下设置错误信息', () => { const errorMsg = '加载数据失败'; const nextState = allHeadcountReducer( initialState, fetchBeginningHeadcount.rejected(new Error(errorMsg), 'req-id') ); expect(nextState.beginningHeadcount.loading).toBe(false); expect(nextState.beginningHeadcount.error).toBe(errorMsg); }); });
三、组件集成测试(结合React Testing Library)
使用自定义的render函数,验证组件与Redux的交互:
import { render, screen, waitFor } from './my.provider'; import HeadcountComponent from './HeadcountComponent'; import { api } from '../path-to-your-api-module'; jest.mock('../path-to-your-api-module', () => ({ api: jest.fn() })); describe('HeadcountComponent', () => { const mockParams = { versionId: 'v1' }; const mockData = [{ id: 1, name: '张三' }]; beforeEach(() => jest.clearAllMocks()); it('加载时显示loading状态', async () => { // 延迟返回API响应,确保loading状态被捕获 (api as jest.Mock).mockImplementation(() => new Promise(resolve => setTimeout(() => resolve({ data: { content: mockData } }), 100)) ); render(<HeadcountComponent versionId={mockParams.versionId} />); expect(screen.getByText('加载中...')).toBeInTheDocument(); }); it('数据加载成功后显示内容', async () => { (api as jest.Mock).mockResolvedValue({ data: { content: mockData, totalElements: 1, totalPages: 1 } }); render(<HeadcountComponent versionId={mockParams.versionId} />); await waitFor(() => expect(screen.getByText('张三')).toBeInTheDocument()); expect(screen.queryByText('加载中...')).not.toBeInTheDocument(); }); it('加载失败时显示错误信息', async () => { (api as jest.Mock).mockRejectedValue(new Error('加载数据失败')); render(<HeadcountComponent versionId={mockParams.versionId} />); await waitFor(() => expect(screen.getByText('加载数据失败')).toBeInTheDocument()); expect(screen.queryByText('加载中...')).not.toBeInTheDocument(); }); });
内容的提问来源于stack exchange,提问作者stratdev
相关产品推荐
相关产品推荐

