简介
编写单元测试对于开发过程是非常重要的。测试使用HTTP请求的组件有时可能是一个真正的痛苦。
在测试中,我们经常想通过模拟请求来测试我们的代码,而不需要实际进行HTTP请求。当我们在测试进行外部API调用的代码时,这可能特别重要,因为我们不想依赖外部API的可用性。
我们将使用一个名为nock的第三方软件包,它可以帮助我们模拟HTTP请求。通过nock,我们可以指定我们的模拟HTTP请求的所需行为,包括URL、头文件和正文。这使我们能够针对已知的数据集测试我们的代码,从而使调试和测试更加直接。
我将展示如何在简单的React应用中通过模拟方法为API调用编写单元测试。
我们将涵盖的步骤:
- 为什么在测试过程中嘲弄HTTP请求是很重要的?
- 什么是Nock?
- 引导示例应用程序
- 添加一个单元测试
- Nock的安装和配置
- Nock中的自定义请求
- 所有的HTTP方法如
GET,POST,PUT,DELETE都可以被模拟。 - 为了处理查询参数,可以使用
query选项。 - 嘲弄服务器错误
- 所有的HTTP方法如
- 在Nock中记录
- 替代的API嘲弄库
为什么在测试中模拟HTTP请求很重要?
模拟测试是加速运行测试的一个好方法,因为你可以消除外部系统和服务器。
这些都是你在用API运行测试时可能遇到的错误:
- 每次请求时,从API返回的数据可能是不同的。
- 需要较长的时间来完成运行测试。
- 你可能会得到一个大的数据,而你不需要在测试中使用。
- 你可能会有诸如速率限制和连接的问题。
我们将使用Nock来寻找这些问题的解决方案。我们将创建一个简单的react应用并请求一个外部API。我们将实现如何模拟API调用,并在React应用中使用Nock为API调用写一个单元测试。
什么是Nock?
Nock是一个HTTP服务器嘲弄和期望库。Nock通过重写Node的http.request 函数来工作。
它帮助我们模拟对API的调用,并指定我们要监听的URL,并以预定义的响应来回应,就像真正的API一样。
我们可以使用nock来测试发出HTTP请求的React组件。
引导示例应用程序
我们将使用superplateCLI向导来快速创建和定制React应用程序。
运行以下命令:
npx superplate-cli example-app
在进行CLI步骤时,选择以下选项:
? Select your project type
❯ react
? Testing Framework
❯ React Testing Library
CLI应该创建一个项目并安装选定的依赖。
用下面的代码创建一个组件:
//index.tsx
export const Main = () => {
const [state, setState] = React.useState<{ firstName: string }>({
firstName: '',
});
const fetchData = async () => {
const response = await fetch(
'https://api.fake-rest.refine.dev/users/1'
);
const result = await response.json();
return result;
};
React.useEffect(() => {
(async () => {
const data = await fetchData();
setState(data);
})();
}, []);
return <div>{state.firstName}</div>;
};
上面我们可以看到,我们对refine的假REST API URL进行了fetch调用,此后返回的数据显示在屏幕上。
添加一个单元测试
现在,我们要创建一个测试文件。
我们要为向URL发出HTTP请求并返回所提供的数据的函数添加一个测试案例。等待API返回的数据在屏幕上呈现是一种典型的测试方式。
使用React测试库,预期的单元测试花瓶将是这样的:
//index.spec.tsx
import { Main } from './index';
import { render, screen, waitFor } from '@testing-library/react';
describe('expectedData', () => {
it('checks if returned data from API rendered into component', async () => {
render(<Main />);
await waitFor(() => {
expect(screen.getByText("/value from the api")).toBeInTheDocument();
});
});
});
在这一点上,如果运行测试,它将失败。它将试图执行一个网络请求。由于我们正在调用一个真正的数据库,它将返回所有的数据,而不是只返回我们需要的特定数据。
另外,API将对每个请求做出不同的响应值。
以这种方式测试这种与HTTP请求相关的架构会让人头疼。
通过nock模拟服务,我们可以拦截对API的请求并返回自定义的响应。
Nock的安装和配置
如果你没有nock,用下面的命令安装它:
npm install --save-dev nock
我们将添加突出显示的代码来初始化nock:
//index.spec.tsx
import { Main } from './index';
import { render, screen, waitFor } from '@testing-library/react';
//===>
import nock from 'nock';
//<===
describe('expectedData', () => {
it('checks if returned data from API rendered into component', async () => {
//===>
nock('https://api.fake-rest.refine.dev')
.defaultReplyHeaders({
'access-control-allow-origin': '*',
})
.get('/users/1')
.reply(200, {
id: 1,
firstName: "/value from the api",
});
//<===
render(<Main />);
await waitFor(() => {
expect(
screen.getByText("/value from the api")
).toBeInTheDocument();
});
});
});
在这一点上,我们的测试工作:
测试运行器用nock创建了一个模拟服务器,fetchData() 方法将被触发。我们
不是调用API来测试我们的应用程序,而是提供一组已知的响应来模拟它。
Nock拦截GET ,请求到'https://api.fake-rest.refine.dev' ,然后是路径'/users/1' ,HTTP方法get 。
响应应该是像在reply() 方法中定义的那样。
我们还将CORS 策略设置为头信息,即defaultReplyHeaders 。
Nock中的自定义请求
我们可以指定模拟请求。
所有的HTTP方法如GET,POST,PUT,DELETE 都可以被模拟。
简单的POST 请求:
nock('https://api.fake-rest.refine.dev')
.post('/users', {
username: 'test',
status: true,
})
.reply(201);
为了处理查询参数,可以使用query 选项:
nock('https://api.fake-rest.refine.dev')
.get('/users')
.query({
username: 'test',
status: true,
})
.reply(200);
当一个HTTP请求以指定的查询进行时,nock将拦截并返回一个200 状态代码。
嘲弄服务器的错误
错误回复可以通过replyWithError prop从嘲讽服务器返回:
nock('https://api.fake-rest.refine.dev')
.get('/users')
.replyWithError({
message: 'Server ERROR',
});
你可能想通过只回复一个状态码来处理错误:
nock('https://api.fake-rest.refine.dev')
.post('/users', {
username: 'test',
status: true,
})
.reply(500);
注意:需要注意的是,我们使用afterAll(nock.restore) 和afterEach(nock.cleanAll) 来确保拦截器不会互相干扰:
afterAll(() => {
nock.cleanAll();
nock.restore();
});
Nock中的记录
录音依赖于拦截真实的请求和响应,然后将其持久化以备后用。
Nock将代码打印到控制台,我们可以用nock.recorder.rec() 方法将其作为测试中的一个响应。
注释掉nock函数,让我们在测试文件中加入nock.recorder.rec() 。
当测试运行时,控制台会记录nock所记录的所有服务调用。
与其手动定义nock 方法和回复值,我们可以使用记录的值。
替代的API嘲弄库
MSW Mock Service Worker。Mock Service Worker是一个API嘲讽库,它使用Service Worker API来拦截实际请求。
Mirage JS:Mirage JS是一个API嘲讽库,它可以让你建立、测试和分享一个完整的工作的JavaScript应用程序,而不需要依赖任何后台服务。
fetch-mock:fetch-mock允许模拟使用fetch或模仿其API的库发出的HTTP请求。
总结
在这篇文章中,我们已经实现了API嘲讽,并解释了它是多么有用。我们在测试中使用了nock来模拟HTTP请求,并展示了一些有用的属性。
我们已经看到了如何孤立地只测试一个应用程序的行为。避免任何可能影响我们测试的外部依赖关系,并确保它们一直运行在稳定的版本上。
构建你的基于React的CRUD应用,不受约束
低代码的React框架对于获得开发速度是很好的,但如果你的项目需要广泛的造型和定制,它们往往在灵活性方面有所欠缺。

refine是一个基于React的框架,用于构建无约束的CRUD应用程序。
它可以将你的开发时间加快3倍,而不影响造型、定制和项目工作流程

