React组件测试:UserList渲染报map读取错误的最佳实践
报错根因
测试运行时抛出TypeError: Cannot read property 'map' of undefined的核心原因:编写测试代码时直接渲染<UserList />,未传入组件运行必须依赖的users属性,组件内部直接对props.users执行map操作时,拿到未定义值触发报错。
原组件未对users属性做兜底处理,实际运行中如果父组件传入空值,也会触发同类崩溃。
测试工具选型
不存在二选一的问题,两类工具是配合使用的关系:
- Jest是测试运行框架,提供测试执行、断言规则、依赖mock的基础能力
- React Testing Library是面向React组件的测试工具集,提供组件渲染、DOM元素查询、用户交互模拟的能力
当前React生态下官方推荐的测试组合就是Jest + React Testing Library,无需额外选型。
UserList组件测试最优实践
UserList属于纯展示型组件,所有渲染依赖都来自父组件传入的props,因此测试时不需要接入真实API、不需要引入上层App组件,手动模拟传入符合格式的props,即可完成UI逻辑的验证。
组件健壮性优化建议
首先为原组件增加属性兜底,避免无prop传入时崩溃:
const UserList = (props) => { // 对可能为undefined的users做兜底,默认空数组 const userList = props.users || []; return ( <Card className={classes.users}> <ul data-testid="ultest"> {userList.map(user => ( <li key={user.id}> <img src={user.avatar} alt={user.id}></img> <div>{user.first_name} {user.last_name} <p><a href={`mailto:${user.email}`}>{user.email}</a></p> </div> </li> ))} </ul> </Card> ) }
可运行的测试用例实现
编写测试时手动传入模拟用户数据,完成渲染逻辑断言:
import React from 'react'; import { render, screen } from '@testing-library/react'; import UserList from '../components/Users/UserList'; import '@testing-library/jest-dom/extend-expect'; // 构造符合组件数据结构要求的模拟用户列表 const mockUsers = [ { id: 1, first_name: "George", last_name: "Bluth", email: "george.bluth@reqres.in", avatar: "https://dummyurl.com/avatar1.png" }, { id: 2, first_name: "Janet", last_name: "Weaver", email: "janet.weaver@reqres.in", avatar: "https://dummyurl.com/avatar2.png" } ]; test('传入有效用户列表时,正确渲染所有用户信息', () => { // 渲染组件时传入依赖的users prop,解决undefined报错 render(<UserList users={mockUsers} />); // 断言用户姓名正常渲染 expect(screen.getByText('George Bluth')).toBeInTheDocument(); expect(screen.getByText('Janet Weaver')).toBeInTheDocument(); // 断言用户邮箱链接正常渲染 expect(screen.getByRole('link', { name: 'george.bluth@reqres.in' })).toBeInTheDocument(); // 断言渲染的列表条目数量和传入数据长度一致 expect(screen.getAllByRole('listitem')).toHaveLength(2); }); test('传入空用户列表时,不渲染用户条目', () => { render(<UserList users={[]} />); // 断言没有匹配到任何列表条目 expect(screen.queryAllByRole('listitem')).toHaveLength(0); });
测试边界说明
- 纯UI组件的单元测试只需验证props和渲染输出的对应关系,不需要模拟接口请求;接口请求的验证属于上层App组件的集成测试范围,需单独对axios做mock,验证App拿到接口数据后能正确传递给UserList组件
- 测试查询元素时优先使用角色、文本内容做匹配,减少对
data-testid的硬依赖,保证测试和用户真实交互感知一致
内容的提问来源于stack exchange,提问作者StillLearning
相关产品推荐
相关产品推荐

