使用 Jest 进行单元测试
了解如何设置和配置 jest-expo 库以使用 Jest 为项目编写单元和快照测试。
Jest 是使用最广泛的 JavaScript 单元测试和快照测试框架。在本指南中,你将学习如何在项目中设置 Jest、编写单元测试、编写快照测试,以及在 React Native 中使用 Jest 时组织测试的最佳实践。
你还将使用 jest-expo 库,它是一个 Jest 预设,用于模拟 Expo SDK 的原生部分,并处理你 Expo 项目所需的大部分配置。
🌐 You will also use the jest-expo library, which is a Jest preset that mocks the native part of the Expo SDK and handles most of the configuration required for your Expo project.
安装和配置
🌐 Installation and configuration
在创建你的 Expo 项目后,请按照以下说明在你的项目中安装和配置 jest-expo:
🌐 After creating your Expo project, follow the instructions below to install and configure jest-expo in your project:
1
在你的项目中安装 jest-expo 及其他所需的开发依赖。在项目根目录下运行以下命令:
🌐 Install jest-expo and other required dev dependencies in your project. Run the following command from your project's root directory:
- 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 的基础配置的预设:
🌐 Open package.json, add a script for running tests, and add the preset for using the base configuration from jest-expo:
{ "scripts": { "test": "jest --watchAll" %%placeholder-start%%... %%placeholder-end%%}, "jest": { "preset": "jest-expo" } }
3
在 package.json 中,添加 jest-expo 作为预设,以便为 Jest 配置设置一个基础:
🌐 In package.json, add jest-expo as a preset so that a base for Jest's configuration is set up:
{ "jest": { "preset": "jest-expo" } }
用于配置 transformIgnorePatterns 的附加设置
你可以通过在你的 package.json 中配置 transformIgnorePatterns 来转译你的项目使用的节点模块。该属性的值为正则表达式模式:
🌐 You can transpile node modules your project uses by configuring transformIgnorePatterns in your package.json. This property takes a regex pattern as its value:
"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 有许多配置选项,但上述配置应能满足大多数需求。不过,你始终可以向此模式列表中添加更多内容。更多详情,请参见 配置 Jest。
🌐 Jest has many configuration options, but the above configuration should cover most of your needs. However, you can always add to this pattern list. For more details, see Configuring Jest.
安装 React Native 测试库
🌐 Install React Native Testing Library
React Native 测试库 (@testing-library/react-native) 是一个用于测试 React Native 组件的轻量级解决方案。它提供了实用函数,并且可与 Jest 一起使用。
🌐 The React Native Testing Library (@testing-library/react-native) is a lightweight solution for testing React Native components. It provides utility functions and works with Jest.
要安装它,请运行以下命令:
🌐 To install it, run the following command:
- 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 文档。
单元测试
🌐 Unit test
单元测试检查代码的最小单元,通常是一个函数。要编写你的第一个单元测试,请看以下示例:
🌐 A unit test checks the smallest unit of code, usually a function. To write your first unit test, take a look at the following example:
1
在项目的 app 目录下,创建一个名为 index.tsx 的新文件,并添加以下代码来渲染一个简单的组件:
🌐 Inside the app directory of your project, create a new file called index.tsx, and the following code to render a simple component:
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 扩展名的文件作为测试文件。
🌐 Create a __tests__ directory at the root of your project's directory. If this directory already exists in your project, use that. Then, create a new file called HomeScreen-test.tsx. The jest-expo preset customizes the Jest configuration to also identify files with -test.ts|tsx extensions as tests.
在 HomeScreen-test.tsx 中添加以下示例代码:
🌐 Add the following example code in 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 测试库提供了这个查询,每个查询变体的返回类型各不相同。有关更多示例和详细的 API 信息,请参阅 React Native 测试库的查询 API 参考。
🌐 In the above example, the getByText query helps your tests find relevant element in your app's user interface and make assertion whether or not the certain element exists. The React Native Testing Library provides this query, and each query variant differs in its return type. For more examples and detailed API information, see the React Native Testing Library's Queries API reference.
3
在终端窗口中运行以下命令以执行测试:
🌐 Run the following command in a terminal window to execute the test:
- npm run test你将看到一个测试通过。
🌐 You will see one test being passed.
构建你的测试
🌐 Structure your tests
整理你的测试文件很重要,这样更容易维护。一种常见的做法是创建一个 tests 目录,并将所有测试文件放在其中。
🌐 Organizing your test files is important to make them easier to maintain. A common pattern is creating a __tests__ directory and putting all your tests inside.
下面展示了位于 components 目录旁的测试示例结构:
🌐 An example structure of tests next to the components directory is shown below:
__tests__ThemedText-test.tsxcomponentsThemedText.tsxThemedView.tsx或者,你可以为项目的不同部分创建多个 tests 子目录。例如,为 components 创建一个单独的测试目录,等等:
🌐 Alternatively, you can have multiple __tests__ sub-directories for different areas of your project. For example, create a separate test directory for components, and so on:
componentsThemedText.tsx__tests__ThemedText-test.tsxutilsindex.tsx__tests__index-test.tsx这完全取决于个人偏好,由你决定如何组织你的项目目录。
🌐 It's all about preferences, and it is up to you to decide how you want to organize your project directory.
快照测试
🌐 Snapshot test
信息 注意: 对于界面测试,我们建议使用端到端测试,而不是快照单元测试。请参阅 使用 Maestro 的端到端测试 指南。
快照测试(snapshot test)用于确保用户界面保持一致,尤其是在项目使用可能跨组件共享的全局样式时。
🌐 A snapshot test is used to make sure that UI stays consistent, especially when a project is working with global styles that are potentially shared across components.
要为 <HomeScreen /> 添加快照测试,请在 HomeScreen-test.tsx 的 describe() 中添加以下代码片段:
🌐 To add a snapshot test for <HomeScreen />, add the following code snippet in the describe() in 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_ 目录下看到一个创建的快照,并且有两个测试通过了。
🌐 Run npm run test command, and you will see a snapshot created inside __tests__\__snapshots__ directory, and two tests passed.
代码覆盖率报告
🌐 Code coverage reports
代码覆盖率报告可以帮助你了解你的代码有多少被测试。要在项目中以 HTML 格式查看代码覆盖率报告,在 package.json 中的 jest 下,将 collectCoverage 设置为 true,并使用 collectCoverageFrom 指定在收集覆盖率时要忽略的文件列表。
🌐 Code coverage reports can help you understand how much of your code is tested. To see the code coverage report in your project using the HTML format, in package.json, under jest, set the collectCoverage to true and use collectCoverageFrom to specify a list of files to ignore when collecting the coverage.
"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 并在浏览器中打开它以查看覆盖率报告。
🌐 Run npm run test. You will see a coverage directory created in your project. Find the lcov-report/index.html and open it in a browser to see the coverage report.
通常,我们不建议将 index.html 文件上传到 Git。可以在 .gitignore 文件中添加
coverage/**/*来防止其被跟踪。
Jest 流程(可选)
🌐 Jest flows (optional)
你也可以使用不同的流程来运行你的测试。下面是一些你可以尝试的示例脚本:
🌐 You can also use different flows to run your tests. Below are a few example scripts that you can try:
"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 选项。
🌐 For more information, see CLI Options in Jest documentation.
附加信息
🌐 Additional information
请参阅 React Native Testing Library 文档,该文档提供测试工具,并鼓励良好的测试实践,同时与 Jest 配合使用。
了解如何在使用 Expo Router 时为你的应用创建集成测试。
了解如何使用 Maestro 在 EAS 工作流上设置和运行端到端测试。