使用 Jest 的单元测试

编辑

了解如何设置和配置 jest-expo 库,以使用 Jest 为项目编写单元测试和快照测试。


Jest 是最常用的单元测试和快照测试的 JavaScript 测试框架。在本指南中,你将学习如何在你的项目中设置 Jest、编写单元测试、编写快照测试,以及在使用 Jest 与 React Native 时对测试结构的最佳实践。

你还将使用 jest-expo 库,它是一个 Jest 预设,仿制 Expo SDK 的原生部分并处理你在 Expo 项目中所需的大部分配置。

安装与配置

创建 Expo 项目后,按以下说明在你的项目中安装和配置 jest-expo

1

在你的项目中安装 jest-expo 和其他所需的开发依赖。请从项目的根目录运行以下命令:

Terminal
npx expo install jest-expo jest @types/jest --dev
Terminal
npx expo install jest-expo jest @types/jest "--" --dev

注: 如果你的项目不使用 TypeScript,可以跳过安装 @types/jest

2

打开 package.json,添加一个用于运行测试的脚本,并添加使用 jest-expo 基本配置的预设:

package.json
{ "scripts": { "test": "jest --watchAll" %%placeholder-start%%... %%placeholder-end%%}, "jest": { "preset": "jest-expo" } }

3

package.json 中,添加 jest-expo 作为 preset,以便为 Jest 的配置设置一个基础:

package.json
{ "jest": { "preset": "jest-expo" } }
使用 transformIgnorePatterns 的其他配置

你可以通过在你的 package.json 中配置 transformIgnorePatterns 来对项目使用的 node_modules 进行转译。该属性接受一个正则表达式模式作为其值:

package.json
"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)" ] }
package.json
"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 一起使用。

要安装,请运行以下命令:

Terminal
npx expo install @testing-library/react-native --dev
Terminal
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 的新文件,并添加以下代码来渲染一个简单组件:

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 中添加以下示例代码:

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

在终端窗口中运行以下命令以执行测试:

Terminal
npm run test

你会看到一个测试通过。

结构化你的测试

组织你的测试文件对于让它们更易于维护非常重要。一个常见的模式是创建一个 __tests__ 目录并将所有测试放在其中。

下面给出一个放在 components 目录旁边的测试示例结构:

__tests__
ThemedText-test.tsx
components
ThemedText.tsx
ThemedView.tsx

或者,你也可以为项目的不同部分创建多个 __tests__ 子目录。例如,为 components 创建一个单独的测试目录,依此类推:

components
ThemedText.tsx
__tests__
  ThemedText-test.tsx
utils
index.tsx
__tests__
  index-test.tsx

一切都关乎偏好,由你来决定如何组织你的项目目录。

快照测试

注意: 对于 UI 测试,我们推荐进行端到端测试,而不是快照单元测试。请参阅 E2E tests with Maestro 指南。

一个 快照测试 用来确保 UI 保持一致,特别是当项目使用全局样式且可能在组件之间共享时。

要为 <HomeScreen /> 添加快照测试,请在 HomeScreen-test.tsxdescribe() 中加入以下代码片段:

HomeScreen-test.tsx
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 指定在收集覆盖率时要忽略的文件列表。

package.json
"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 流程(可选)

您也可以使用不同的流程来运行测试。下面是一些可尝试的示例脚本:

package.json
"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 文档

请参阅 React Native Testing Library 的文档,其中提供了测试工具并鼓励良好的测试实践,以及与 Jest 的协作。

针对 Expo Router 的测试配置

了解在使用 Expo Router 时如何为应用创建集成测试。

使用 EAS 工作流的端到端测试

了解如何在 EAS Workflows 上设置并运行端到端测试,使用 Maestro。