许多开发人员在测试代码时面临挑战。如果没有适当的测试,错误可能会溜走,导致用户沮丧和昂贵的修复。
本文将向您展示如何在使用 Node.js 和 MongoDB 构建的非常简单的示例中使用 Jest、Supertest 和 Puppeteer 有效应用单元、集成和端到端测试。
读完本文,我希望您能够清楚地了解如何在自己的项目中应用这些类型的测试。
??请在此存储库中找到完整的示例。
在安装依赖项之前,让我先介绍一下我们的示例。这是一个非常简单的示例,用户可以打开注册页面,设置其注册详细信息,单击注册按钮,并将其信息存储在数据库中。
在此示例中,我们将使用以下包:
npm install --save jest express mongoose validator npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all
大多数依赖项都很简单,但以下是其中一些依赖项的说明:
很好,让我们将其翻译成代码。
为了运行单元测试而没有不可预测的行为,您应该在每次测试之前重置模拟函数。您可以使用 beforeEach 挂钩来实现此目的:
// setup.unit.js beforeEach(() => { jest.resetAllMocks(); jest.restoreAllMocks(); });
在本例中,我们要测试 validateInput 函数:
npm install --save jest express mongoose validator npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all
这是一个非常简单的函数,用于验证提供的输入是否包含有效的电子邮件。这是它的单元测试:
// setup.unit.js beforeEach(() => { jest.resetAllMocks(); jest.restoreAllMocks(); });
await Expect(async () => {}).rejects:根据 Jest 文档,这是期望被拒绝的 Promise 原因的方法。
让我们测试另一个函数,检查数据库中是否存在重复的电子邮件。实际上,这一点很有趣,因为我们必须处理数据库,同时单元测试不应该处理外部系统。那我们该怎么办呢?好吧,我们应该使用 Mocks。
首先,看看我们需要测试的 emailShouldNotBeDuplicated 函数:
// register.controller.js const validator = require('validator'); const registerController = async (input) => { validateInput(input); ... }; const validateInput = (input) => { const { name, email, password } = input; const isValidName = !!name && validator.isLength(name, { max: 10, min: 1 }); if (!isValidName) throw new Error('Invalid name'); ... };
如您所见,此函数向数据库发送请求以检查是否有其他用户具有相同的电子邮件地址。以下是我们如何模拟数据库调用:
// __tests__/unit/register.test.js const { registerController } = require('../controllers/register.controller'); describe('RegisterController', () => { describe('validateInput', () => { it('should throw error if email is not an email', async () => { const input = { name: 'test', email: 'test', password: '12345678' }; await expect(async () => await registerController(input)).rejects.toThrow('Invalid email'); }); }); });
我们使用 jest.spyOn(object, methodName) 模拟(监视)数据库 findOne 方法,该方法创建一个模拟函数并跟踪其调用。因此,我们可以使用 toHaveBeenNthCalledWith 来跟踪监视的 findOne 方法的调用次数和传递的参数。
在编写集成测试之前,我们必须配置我们的环境:
npm install --save jest express mongoose validator npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all
现在,我们已准备好运行集成测试。
让我们测试整个服务器端注册过程——从发送注册请求到将用户详细信息存储在数据库中并重定向到成功页面:
// setup.unit.js beforeEach(() => { jest.resetAllMocks(); jest.restoreAllMocks(); });
如您所见,registerController 函数集成了多个组件(函数),validateInput、emailShouldNotBeDuplicated 和 createUser 函数。
那么,让我们编写集成测试:
// register.controller.js const validator = require('validator'); const registerController = async (input) => { validateInput(input); ... }; const validateInput = (input) => { const { name, email, password } = input; const isValidName = !!name && validator.isLength(name, { max: 10, min: 1 }); if (!isValidName) throw new Error('Invalid name'); ... };
让我们开始我们的示例。
实际上,在我们的示例中,端到端测试的环境配置与集成测试类似。
在这种情况下,我们需要准确模拟真实的用户注册行为,从打开注册页面,填写详细信息(姓名、电子邮件、密码),单击“注册”按钮,最后重定向到成功页面。看一下代码:
npm install --save jest express mongoose validator npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all
让我们分解一下这段代码:
照片由 Nathan Dumlao 在 Unsplash 上拍摄
此时,您可能想知道当每个测试类型都有自己的配置时如何同时运行所有测试类型。例如:
那么,我们如何同时运行所有测试类型,同时确保每个测试类型遵循其相应的配置?
要解决此问题,请按照以下步骤操作:
1. 让我们创建三个不同的配置文件,jest.unit.config.js:
// setup.unit.js beforeEach(() => { jest.resetAllMocks(); jest.restoreAllMocks(); });
jest.integration.config.js:
// register.controller.js const validator = require('validator'); const registerController = async (input) => { validateInput(input); ... }; const validateInput = (input) => { const { name, email, password } = input; const isValidName = !!name && validator.isLength(name, { max: 10, min: 1 }); if (!isValidName) throw new Error('Invalid name'); ... };
jest.e2e.config.js:
// __tests__/unit/register.test.js const { registerController } = require('../controllers/register.controller'); describe('RegisterController', () => { describe('validateInput', () => { it('should throw error if email is not an email', async () => { const input = { name: 'test', email: 'test', password: '12345678' }; await expect(async () => await registerController(input)).rejects.toThrow('Invalid email'); }); }); });
2. 接下来,更新 package.json 文件中的 npm 脚本,如下所示:
// register.controller.js const { User } = require('../models/user'); const registerController = async (input) => { ... await emailShouldNotBeDuplicated(input.email); ... }; const emailShouldNotBeDuplicated = async (email) => { const anotherUser = await User.findOne({ email }); if (anotherUser) throw new Error('Duplicated email'); };
--config:指定 Jest 配置文件的路径。
npm-run-all --parallel:允许并行运行所有测试。
3. 然后,创建三个名为 setup.unit.js、setup.integration.js 和 setup.e2e.js 的安装文件,其中包含前面部分中使用的必要安装代码。
4. 最后,通过执行此命令 npm run test 来运行所有测试。该命令将根据各自的配置并行执行所有单元、集成和端到端测试。
在本文中,我们探讨了单元、集成和端到端 (E2E) 测试,强调它们对于构建可靠应用程序的重要性。我们在 Node.js 和 MongoDB 的简单用户注册示例中演示了如何使用 Jest、Supertest 和 Puppeteer 来实现这些测试方法。
事实上,可靠的测试策略不仅可以提高代码质量,还可以增强开发人员的信心并提高用户满意度。
我希望这篇文章为您提供了有用的见解,您可以将其应用到您自己的项目中。测试愉快!
如果您发现本文有用,请查看以下文章:
非常感谢您一直陪伴我到现在。我希望您喜欢阅读这篇文章。
以上是使用 Jest 的一个示例中的单元、集成和 ETesting的详细内容。更多信息请关注PHP中文网其他相关文章!