使用 Jest 进行单元测试

编辑页面

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


For the complete documentation index, see llms.txt. Use this Use this file to discover all available pages.

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

你还将使用 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

如果你的项目使用 TypeScript,请将 "jest" 添加到 tsconfig.json 中的 types 数组,以启用 Jest 的类型定义:

tsconfig.json
{ "compilerOptions": { "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 作为预设,以便为 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 有许多配置选项,但以上配置应能满足你大部分需求。不过,你始终可以继续向这个模式列表中添加内容。更多详情请参阅 配置 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 文档

单元测试

单元测试用于检查最小的代码单元,通常是一个函数。要编写你的第一个单元测试,请看下面的示例:

1

在项目的 src/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>欢迎!</CustomText> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, });

2

在项目根目录创建一个 tests 目录。如果项目中已经存在这个目录,就使用现有目录。然后创建一个名为 home-screen-test.tsx 的新文件。jest-expo 预设会自定义 Jest 配置,使其也能将带有 -test.ts|tsx 扩展名的文件识别为测试。

home-screen-test.tsx 中添加以下示例代码:

home-screen-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 提供了这个查询,而且每种 查询变体 的返回类型都不同。更多示例和详细 API 信息,请参阅 React Native Testing Library 的 查询 API 参考

3

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

Terminal
npm run test

你会看到一个测试通过。

组织测试结构

整理测试文件很重要,这样更便于维护。一个常见模式是创建一个 tests 目录,并将所有测试放在其中。

下面展示了一个与 components 目录并列的测试结构示例:

__tests__
themed-text-test.tsx
src
components
  themed-text.tsx
  themed-view.tsx

或者,你也可以为项目的不同区域设置多个 tests 子目录。例如,为 components 单独创建一个测试目录,等等:

src
components
  themed-text.tsx
  __tests__
   themed-text-test.tsx
utils
  index.tsx
  __tests__
   index-test.tsx

这完全取决于你的偏好,由你来决定如何组织项目目录。

快照测试

信息 **注意:**对于 UI 测试,我们建议使用端到端测试而不是快照单元测试。请参阅使用 Maestro 的 E2E 测试 指南。

快照测试 用于确保 UI 保持一致,尤其是在项目使用可能在各组件之间共享的全局样式时。

要为 <HomeScreen /> 添加快照测试,请在 home-screen-test.tsx 中的 describe() 内添加以下代码片段:

home-screen-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 目录中创建了一个快照,并且有两个测试通过。

代码覆盖率报告

代码覆盖率报告可以帮助你了解有多少代码得到了测试。要以 HTML 格式查看项目中的代码覆盖率报告,请在 package.jsonjest 下将 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 选项

其他信息

React Native Testing library 文档

查看 React Native Testing Library 文档,它提供测试工具并鼓励良好的测试实践,并与 Jest 配合使用。

Expo Router 的测试配置

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

使用 EAS Workflows 的 E2E 测试

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