使用 Jest 的单元测试
编辑
了解如何设置和配置 jest-expo 库,以使用 Jest 为项目编写单元测试和快照测试。
Jest 是最常用的单元测试和快照测试的 JavaScript 测试框架。在本指南中,你将学习如何在你的项目中设置 Jest、编写单元测试、编写快照测试,以及在使用 Jest 与 React Native 时对测试结构的最佳实践。
你还将使用 jest-expo 库,它是一个 Jest 预设,仿制 Expo SDK 的原生部分并处理你在 Expo 项目中所需的大部分配置。
安装与配置
创建 Expo 项目后,按以下说明在你的项目中安装和配置 jest-expo:
1
在你的项目中安装 jest-expo 和其他所需的开发依赖。请从项目的根目录运行以下命令:
- npx expo install jest-expo jest @types/jest --dev- npx expo install jest-expo jest @types/jest "--" --dev注: 如果你的项目不使用 TypeScript,可以跳过安装
@types/jest。
2
打开 package.json,添加一个用于运行测试的脚本,并添加使用 jest-expo 基本配置的预设:
{ "scripts": { "test": "jest --watchAll" %%placeholder-start%%... %%placeholder-end%%}, "jest": { "preset": "jest-expo" } }
3
在 package.json 中,添加 jest-expo 作为 preset,以便为 Jest 的配置设置一个基础:
{ "jest": { "preset": "jest-expo" } }
使用 transformIgnorePatterns 的其他配置
你可以通过在你的 package.json 中配置 transformIgnorePatterns 来对项目使用的 node_modules 进行转译。该属性接受一个正则表达式模式作为其值:
"jest": { "preset": "jest-expo", "transformIgnorePatterns": [ "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg)" ] }
"jest": { "preset": "jest-expo", "transformIgnorePatterns": [ "node_modules/(?!(?:.pnpm/)?((jest-)?react-native|@react-native(-community)?|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg))" ] }
Jest 有大量的配置选项,但上述配置应覆盖大部分需求。不过,你始终可以向此模式列表添加更多项。有关更多细节,请参阅 Configuring Jest。
安装 React Native Testing Library
React Native Testing Library (@testing-library/react-native) 是一个用于测试 React Native 组件的轻量级解决方案。它提供实用函数,并可与 Jest 一起使用。
要安装,请运行以下命令:
- npx expo install @testing-library/react-native --dev- npx expo install @testing-library/react-native "--" --dev已弃用:@testing-library/react-native取代了已弃用的react-test-renderer,因为react-test-renderer不支持 React 19 及以上版本。如果你当前在使用它,请从项目中移除该已弃用的库。有关更多信息,请参阅 React 的文档 React's documentation for more information。
Unit test
一个单元测试检查代码中最小的单元,通常是一个函数。要编写你的第一个单元测试,请看下面的示例:
1
在你项目的 app 目录中,创建一个名为 index.tsx 的新文件,并添加以下代码来渲染一个简单组件:
import { PropsWithChildren } from 'react'; import { StyleSheet, Text, View } from 'react-native'; export const CustomText = ({ children }: PropsWithChildren) => <Text>{children}</Text>; export default function HomeScreen() { return ( <View style={styles.container}> <CustomText>Welcome!</CustomText> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, });
2
在你的项目根目录下创建一个 __tests__ 目录。如果该目录在你的项目中已经存在,请使用现有的目录。然后,创建一个名为 HomeScreen-test.tsx 的新文件。jest-expo 预设会自定义 Jest 配置,此外还会将扩展名为 -test.ts|tsx 的文件识别为测试文件。
在 HomeScreen-test.tsx 中添加以下示例代码:
import { render } from '@testing-library/react-native'; import HomeScreen, { CustomText } from '@/app/index'; describe('<HomeScreen />', () => { test('Text renders correctly on HomeScreen', () => { const { getByText } = render(<HomeScreen />); getByText('Welcome!'); }); });
在上面的示例中,getByText 查询帮助你的测试在应用的用户界面中找到相关元素,并对该元素是否存在进行断言。React Native Testing Library 提供了此查询,每个 query 变体 在返回类型上有所不同。欲了解更多示例和详细 API 信息,请参阅 React Native Testing Library 的 Queries API reference。
3
在终端窗口中运行以下命令以执行测试:
- npm run test你会看到一个测试通过。
结构化你的测试
组织你的测试文件对于让它们更易于维护非常重要。一个常见的模式是创建一个 __tests__ 目录并将所有测试放在其中。
下面给出一个放在 components 目录旁边的测试示例结构:
__tests__ThemedText-test.tsxcomponentsThemedText.tsxThemedView.tsx或者,你也可以为项目的不同部分创建多个 __tests__ 子目录。例如,为 components 创建一个单独的测试目录,依此类推:
componentsThemedText.tsx__tests__ThemedText-test.tsxutilsindex.tsx__tests__index-test.tsx一切都关乎偏好,由你来决定如何组织你的项目目录。
快照测试
注意: 对于 UI 测试,我们推荐进行端到端测试,而不是快照单元测试。请参阅 E2E tests with Maestro 指南。
一个 快照测试 用来确保 UI 保持一致,特别是当项目使用全局样式且可能在组件之间共享时。
要为 <HomeScreen /> 添加快照测试,请在 HomeScreen-test.tsx 的 describe() 中加入以下代码片段:
describe('<HomeScreen />', () => { %%placeholder-start%%... %%placeholder-end%% test('CustomText renders correctly', () => { const tree = render(<CustomText>Some text</CustomText>).toJSON(); expect(tree).toMatchSnapshot(); }); });
运行 npm run test 命令,你将会在 __tests__\__snapshots__ 目录看到一个快照被创建,并且有两个测试通过。
Code coverage 报告
Code coverage 报告可以帮助你了解有多少代码被测试到。若要在你的项目中以 HTML 格式查看代码覆盖率报告,在 package.json 中,在 jest 下,将 collectCoverage 设置为 true,并使用 collectCoverageFrom 指定在收集覆盖率时要忽略的文件列表。
"jest": { ... "collectCoverage": true, "collectCoverageFrom": [ "**/*.{ts,tsx,js,jsx}", "!**/coverage/**", "!**/node_modules/**", "!**/babel.config.js", "!**/expo-env.d.ts", "!**/.expo/**" ] }
运行 npm run test。你将看到在你的项目中创建一个 coverage 目录。找到 lcov-report/index.html 并在浏览器中打开它以查看覆盖率报告。
通常,我们不建议将 index.html 文件上传到 git。请在 .gitignore 文件中添加
coverage/**/*,以防止被追踪。
Jest 流程(可选)
您也可以使用不同的流程来运行测试。下面是一些可尝试的示例脚本:
"scripts": { "test": "jest --watch --coverage=false --changedSince=origin/main", "testDebug": "jest -o --watch --coverage=false", "testFinal": "jest", "updateSnapshots": "jest -u --coverage=false" %%placeholder-start%%... %%placeholder-end%% }
有关更多信息,请参阅 Jest 文档中的 CLI Options。
附加信息
请参阅 React Native Testing Library 的文档,其中提供了测试工具并鼓励良好的测试实践,以及与 Jest 的协作。
了解在使用 Expo Router 时如何为应用创建集成测试。
了解如何在 EAS Workflows 上设置并运行端到端测试,使用 Maestro。