在现代 Web 开发中,测试是至关重要的一步。使用测试工具可以减少出现错误的概率并使得开发步骤更加流畅。 Jest 是一个流行的 JavaScript 测试框架,它拥有用户友好的接口和强大的 API。 在本文中,我们将介绍如何使用 Jest 测试 Node.js 应用程序。
安装 Jest
安装 Jest 只需要一个命令:
npm install --save-dev jest
这将在项目中安装 Jest 并将其添加到 devDependencies
里。
编写测试
我们来编写一个简单的测试,它将检查一个函数是否正确的返回字符串。
// functions.js function greet(name) { return `Hello ${name}!`; } module.exports = { greet };
// functions.test.js const { greet } = require('./functions'); test('Should return a greeting with the correct name', () => { const name = 'Bob'; expect(greet(name)).toBe(`Hello ${name}!`); });
在上面的代码中,我们创建了一个名为 greet
的函数并导出该函数。 然后我们创建了一个测试文件,并导入该函数以进行测试。
测试使用了 Jest 的 test
方法来定义测试。 这个测试将检查函数的结果是否与期望的结果一致,即字符串 "Hello Bob!"。 我们使用了 Jest 的 expect
方法来进行断言。
运行测试
在执行测试之前,我们需要在 package.json
文件中添加一个命令来运行测试。
// package.json { "scripts": { "test": "jest" } }
现在我们可以使用以下命令来运行我们的测试:
npm test
这将运行我们的所有测试,并且 Jest 将会打印测试成功或失败的结果。
深入测试与指导意义
现在我们已经介绍了一个简单的测试,我们将深入探讨 Jest 的更多功能和指导意义。
测试套件和测试用例
Jest 中的测试都是根据测试套件和测试用例来组织的。
测试套件是一组测试用例。 Jest 使用 describe
函数来定义测试套件。 这个函数需要两个参数:一个测试套件的名称和一个测试套件的定义函数。
测试用例是测试套件中的一个单独测试。 Jest 使用 test
函数来定义测试用例。 这个函数需要两个参数:测试用例的名称和定义函数。
下面是一个测试套件的例子:
describe('Array', () => { describe('#indexOf()', () => { test('should return -1 when the value is not present', () => { expect([1, 2, 3].indexOf(4)).toBe(-1); }); }); });
在上面的代码中,我们创建了一个名为 Array
的测试套件,它包含了一个名为 indexOf
的方法。 其中,我们定义了一个测试用例,它将被称为 “should return -1 when the value is not present”。
断言
在测试中,断言用于检查我们的代码是否工作正常。 Jest 中有很多不同的断言。 在上面的例子中,我们使用了 toBe
断言来检查函数的返回值是否等于我们期望的值。 除此之外,还有其他一些常用的断言,如 toEqual
和 toMatch
。
在测试过程中,我们希望尽可能清晰地表达我们所要测试的东西,以便于理解和进行 debug。
除了简单的断言之外,Jest 还提供了其他一些有用的测试工具,如快照测试和模拟。
快照测试
快照测试用于检查组件是否正确地渲染。 在快照测试中,我们将组件渲染为一个 JSON 对象,并将其与存储在文件中的预期输出进行比较。如果 JSON 对象匹配,则测试通过。
import React from 'react'; import renderer from 'react-test-renderer'; import App from './App'; test('App component should render correctly', () => { const tree = renderer.create(<App />).toJSON(); expect(tree).toMatchSnapshot(); });
在上面的代码中,我们创建了一个名为 App
的 React 组件,并使用 Jest 的 renderer
函数将其渲染为 JSON 对象。 然后,我们使用 toMatchSnapshot
断言来比较组件渲染结果与预期快照是否相同。
模拟
模拟用于在测试中模拟外部依赖。在 Node.js 应用程序中使用模拟可以使我们无需实际触发某些行为就能测试已编写的代码。
以下是在 Node.js 应用程序中使用模拟的例子:
// javascriptcn.com 代码示例 // user.js const axios = require('axios'); async function getUser(id) { const user = await axios.get(`https://jsonplaceholder.typicode.com/users/${id}`); return user.data; } module.exports = { getUser };
// javascriptcn.com 代码示例 // user.test.js const axios = require('axios'); const { getUser } = require('./user'); jest.mock('axios'); test('Should fetch user data', async () => { const data = { name: 'Bob' }; axios.get.mockResolvedValue({ data }); const user = await getUser(1); expect(user).toEqual(data); });
在上面的代码中,我们创建了一个名为 getUser
的函数,它使用 axios
进行 HTTP 请求并返回用户数据。 在 user.test.js
文件中,我们使用 Jest 的 mock
函数来模拟 axios
对象,并使用 mockResolvedValue
方法返回一个用于测试的虚假数据。然后我们调用测试对象,它的行为就像像真实环境一样的代码,我们使用 toEqual
断言方法来检查结果是否和我们预期的一样。
集成测试
集成测试为我们提供了一个在系统的不同部分之间运行测试代码的方式,它可以确保系统的所有部分都能够良好地协同工作。 通常,集成测试是最后一步,需要在代码已构建完全并首次完成时执行。
// javascriptcn.com 代码示例 // app.js const express = require('express'); const bodyParser = require('body-parser'); const userRouter = require('./routes/user'); const app = express(); app.use(bodyParser.json()); app.use('/users', userRouter); module.exports = app;
接下来,我们可以编写一个测试,来测试我们的应用程序是否能够正确的响应请求。
// javascriptcn.com 代码示例 // app.test.js const request = require('supertest'); const app = require('./app'); describe('Test user routes', () => { test('Should create a new user', async () => { const response = await request(app) .post('/users') .send({ name: 'Bob' }); expect(response.status).toBe(201); expect(response.body).toHaveProperty('name', 'Bob'); }); });
在上面的代码中,我们使用 Jest 和 supertest
测试库来测试我们的 app
文件。 我们定义了一个名为 "Test user routes" 的测试套件,并编写了一个测试用例,以检查是否能够成功创建一个新用户。 我们使用链式调用来向我们的应用程序发出 POST
请求并断言返回的响应代码是否为 201
。 我们还使用了 toHaveProperty
断言方法来检查 response.body
中的属性是否符合预期。
总结
Jest 是一个功能强大的 JavaScript 测试框架,它提供了一些强大的 API 和用户友好的接口,使得测试过程变得简单并且效果很好。 在本文中,我们了解了如何安装 Jest,编写真实的测试文件,以及一些高级测试技术。 我们希望这篇文章对 Node.js 应用程序的开发者和测试人员都有所帮助,并带给他们更加流畅和有效的开发体验。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/653f77e17d4982a6eb90935d