Using Mocks for Testing in JavaScript with Jest
介绍
Jest是一种流行的JavaScript开放源代码测试框架。 我们可以使用Jest在测试中创建模拟-在测试代码时替换对象的对象。
在之前的有关使用Sinon.js的单元测试技术的系列文章中,我们介绍了如何使用Sinon.js存根,监视和模拟Node.js应用程序-特别是HTTP调用。
在本系列中,我们将使用Jest涵盖Node.js中的单元测试技术。 Jest由Facebook创建,并与React,Angular和Vue等许多JavaScript库和框架很好地集成在一起。 它特别关注简单性和性能。
在本文中,我们将回顾什么是模拟,然后重点介绍如何在测试中为Node.js应用程序设置Jest以模拟HTTP调用。 然后,我们将比较如何使用Jest和Sinon为程序创建模拟。
什么是Mo子?
在单元测试中,模拟为我们提供了对依赖项提供的功能进行存根的功能,并提供了一种观察代码如何与依赖项进行交互的方法。 当将依赖直接包含在我们的测试中非常昂贵或不切实际时,例如在您的代码正在对API进行HTTP调用或与数据库层进行交互的情况下,模拟是非常有用的。
最好为这些依赖项存根响应,同时确保按需调用它们。 这是模拟派上用场的地方。
现在让我们看看如何使用Jest在Node.js中创建模拟。
在Node.js应用程序中设置Jest
在本教程中,我们将设置一个Node.js应用程序,该应用程序将对包含相册中的照片的JSON API进行HTTP调用。 在我们的测试中,将使用Jest模拟API调用。
首先,让我们创建文件将驻留并移动到的目录:
1 | $ mkdir PhotoAlbumJest && cd PhotoAlbumJest |
然后,让我们使用默认设置初始化Node项目:
1 | $ npm init -y |
项目初始化后,我们将继续在目录的根目录下创建
1 | $ touch index.js |
为了帮助我们处理HTTP请求,我们将使用Axios。
设置Axios
我们将使用
首先安装它:
1 | $ npm i axios --save |
在使用
例如,我们可以为一组HTTP请求(最常见的是为所有HTTP请求使用的基本URL)设置授权标头。
让我们创建配置文件:
1 | touch axiosConfig.js |
现在,让我们访问
1 2 3 4 5 6 7 | const axios = require('axios'); const axiosInstance = axios.default.create({ baseURL: 'https://jsonplaceholder.typicode.com/albums' }); module.exports = axiosInstance; |
设置
在我们之前创建的
1 2 3 4 5 6 7 8 9 10 11 12 | const axios = require('./axiosConfig'); const getPhotosByAlbumId = async (id) => { const result = await axios.request({ method: 'get', url: `/${id}/photos?_limit=3` }); const { data } = result; return data; }; module.exports = getPhotosByAlbumId; |
要使用我们的API,我们只需使用
我们传递给
现在,让我们为此功能设置一个Jest测试。
设置笑话
要设置Jest,我们必须首先使用
1 | $ npm i jest -D |
然后,我们将继续为Jest创建一个名为
1 | touch jest.config.js |
现在,在
1 2 3 4 5 6 7 | module.exports = { testMatch: [ '<rootDir>/**/__tests__/**/?(*.)(spec|test).js', '<rootDir>/**/?(*.)(spec|test).js' ], testEnvironment: 'node', }; |
注意:在JavaScript中,通常会看到测试文件以
现在,让我们修改
1 2 3 | "scripts": { "test":"jest" }, |
我们的设置完成。 要测试我们的配置是否有效,请在名为
1 | touch index.spec.js |
现在,在文件中,让我们编写一个测试:
1 2 3 4 5 | describe('sum of 2 numbers', () => { it(' 2 + 2 equal 4', () => { expect(2 + 2).toEqual(4) }); }); |
使用以下命令运行此代码:
1 | $ npm test |
您应该得到以下结果:
1 2 3 4 5 6 7 8 9 | PASS ./index.spec.js sum of 2 numbers ? 2 + 2 equal 4 (3ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 0.897s, estimated 1s Ran all test suites. |
正确设置了Jest之后,我们现在可以继续编写代码以模拟我们的HTTP调用。
嘲笑HTTP呼叫
在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | const axios = require('./axiosConfig'); const getPhotosByAlbumId = require('./index'); jest.mock('./axiosConfig', () => { return { baseURL: 'https://jsonplaceholder.typicode.com/albums', request: jest.fn().mockResolvedValue({ data: [ { albumId: 3, id: 101, title: 'incidunt alias vel enim', url: 'https://via.placeholder.com/600/e743b', thumbnailUrl: 'https://via.placeholder.com/150/e743b' }, { albumId: 3, id: 102, title: 'eaque iste corporis tempora vero distinctio consequuntur nisi nesciunt', url: 'https://via.placeholder.com/600/a393af', thumbnailUrl: 'https://via.placeholder.com/150/a393af' }, { albumId: 3, id: 103, title: 'et eius nisi in ut reprehenderit labore eum', url: 'https://via.placeholder.com/600/35cedf', thumbnailUrl: 'https://via.placeholder.com/150/35cedf' } ] }), } }); |
在这里,我们首先使用
对于factory参数,我们指定模拟
我们在此处定义的
重要的是
通常,这是通过
放置好模拟后,让我们继续进行测试:
1 2 3 4 5 6 7 8 9 10 11 | describe('test getPhotosByAlbumId', () => { afterEach(() => jest.resetAllMocks()); it('fetches photos by album id', async () => { const photos = await getPhotosByAlbumId(3); expect(axios.request).toHaveBeenCalled(); expect(axios.request).toHaveBeenCalledWith({ method: 'get', url: '/3/photos?_limit=3' }); expect(photos.length).toEqual(3); expect(photos[0].albumId).toEqual(3) }); }); |
在每个测试用例之后,我们确保调用
在我们的测试案例中,我们调用ID为
第一个断言期望调用
让我们使用以下命令运行新测试:
1 | npm test |
我们应该得到以下结果:
1 2 3 4 5 6 7 8 9 | PASS ./index.spec.js test getPhotosByAlbumId ? fetches photos by album id (7ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 0.853s, estimated 1s Ran all test suites. |
有了这种新的熟悉程度和经验,让我们快速比较一下Jest和Sinon的测试经验,后者也经常用于模拟。
锡诺·穆克斯vs笑话
Sinon.js和Jest具有不同的处理模拟概念的方式。 以下是需要注意的一些主要区别:
在Jest中,将模拟文件放在
在Jest中,我们使用
Jest提供了许多方法来使用其模拟API,尤其是模块。您可以在此处查看所有这些信息。另一方面,Sinon.js的模拟方法更少,并且公开了一个更简单的API。
Sinon.js模拟程序作为Sinon.js库的一部分提供,该库可以插入并与其他测试框架(如Mocha)和断言库(如Chai)结合使用。另一方面,Jest模拟是Jest框架的一部分,Jest框架还附带了自己的assertions API。
当您测试可能不需要像Jest这样的框架的全部功能的小型应用程序时,Sinn.js模拟通常是最有益的。 当您已经有测试设置并且需要向应用程序中的一些组件添加模拟时,它也很有用。
但是,当使用具有许多依赖关系的大型应用程序时,充分利用Jest的模拟API及其框架将对确保一致的测试体验非常有利。
结论
在本文中,我们研究了如何使用Jest模拟使用
要了解有关Jest模拟的更多信息以及如何将其用于更高级的用例,请在此处查看其文档。
与往常一样,本教程中的代码可以在GitHub上找到。