如何在useEffect中使用axios请求测试反应组件?
Posted
技术标签:
【中文标题】如何在useEffect中使用axios请求测试反应组件?【英文标题】:How to test react component with axios request in useEffect? 【发布时间】:2022-01-23 18:25:45 【问题描述】:我已经在 useEffect 中根据请求对功能组件做出反应。 https://codesandbox.io/s/nifty-dew-r2p1d?file=/src/App.tsx
const App = () =>
const [data, setData] = useState<IJoke | undefined>(undefined);
const [isLoading, setIsLoading] = useState<boolean>(true);
useEffect(() =>
axios
.get("https://v2.jokeapi.dev/joke/Programming?type=single")
.then((res: AxiosResponse<IJoke>) =>
setData(res.data);
)
.catch((err) => console.log(err))
.finally(() => setIsLoading(false));
, []);
return (
<div className="App">
isLoading ? (
<h2>Loading...</h2>
) : (
<div className="info">
<div className="info__cat">
data?.category ? `category: $data.category` : "bad category"
</div>
<div className="info__joke">
data?.joke ? `joke: $data?.joke` : "bad data"
</div>
</div>
)
</div>
);
;
如何使用测试覆盖组件?我需要在请求之前、及时和之后测试状态。在这种情况下如何模拟请求?
【问题讨论】:
【参考方案1】:您无法通过 react-testing-library 在内部访问 state
和 setState
。这是因为 RTL 希望您像用户一样测试您的组件。
您应该尝试重现更改状态的一组操作。
使用react-testing-library
的render
函数渲染组件,将模拟的state
和setState
传递给该组件。
使用axios
中的axiosMock
模拟axios。
在这种方法中,您可以将模拟值作为真实的本地状态进行检查。
import render from "react-testing-library";
import axiosMock from "axios";
此链接可能会有所帮助:
async-axios-react-testing-library
【讨论】:
【参考方案2】:选项1.使用msw通过拦截网络级别的请求来模拟。
选项 2。如果您不想安装任何软件包和设置,您可以使用 jest.spyOn(object, 'method').mockResolvedValueOnce()
为 axios.get()
方法创建模拟解析/拒绝值。
以下示例使用选项 2。
App.tsx
:
import axios, AxiosResponse from 'axios';
import React, useEffect, useState from 'react';
interface IJoke
category: string;
joke: string;
export const App = () =>
const [data, setData] = useState<IJoke | undefined>(undefined);
const [isLoading, setIsLoading] = useState<boolean>(true);
useEffect(() =>
axios
.get('https://v2.jokeapi.dev/joke/Programming?type=single')
.then((res: AxiosResponse<IJoke>) =>
setData(res.data);
)
.catch((err) => console.log(err))
.finally(() => setIsLoading(false));
, []);
return (
<div className="App">
isLoading ? (
<h2>Loading...</h2>
) : (
<div className="info">
<div className="info__cat">data?.category ? `category: $data.category` : 'bad category'</div>
<div className="info__joke">data?.joke ? `joke: $data?.joke` : 'bad data'</div>
</div>
)
</div>
);
;
App.test.tsx
:
import App from './App';
import axios, AxiosResponse from 'axios';
import act, render, screen from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import React from 'react';
describe('70450576', () =>
afterEach(() =>
jest.restoreAllMocks();
);
test('should render category and joke', async () =>
const mAxiosResponse =
data: category: 'smart', joke: 'sam' ,
as AxiosResponse;
jest.spyOn(axios, 'get').mockResolvedValueOnce(mAxiosResponse);
render(<App />);
expect(screen.getByText('Loading...')).toBeInTheDocument();
expect(await screen.findByText('category: smart')).toBeInTheDocument();
expect(await screen.findByText('joke: sam')).toBeInTheDocument();
);
);
测试结果:
PASS examples/70450576/App.test.tsx (8.874 s)
70450576
✓ should render category and joke (43 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 91.67 | 72.22 | 80 | 90.91 |
App.tsx | 91.67 | 72.22 | 80 | 90.91 | 19
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 9.393 s, estimated 10 s
【讨论】:
好的,我知道如何测试这种情况了,谢谢))但是,如果我们有自定义请求功能,比如link?如何模拟这个函数? @СлаваИванов 你从一个模块中导入一个函数,它不是一个对象,不能再使用jest.spyOn(object, 'method')
。现在,您可以使用jest.mock("./app.service")
来模拟模块。 Jest 会自动将 jest.mock
调用提升到模块顶部(在任何导入之前)。 getJoke
函数被模拟,然后您可以模拟每个测试用例中已解析/拒绝的值,例如 getJoke.mockResolvedValueOnce(xxx)
。此外,您可以使用 ts-jest/utils
中的 mocked
辅助函数来使 TS 类型正确。跨度>
+1 用于使用 MSW。不要模拟您的请求客户端/功能的实现细节。而是在更高级别上进行 API 模拟。以上是关于如何在useEffect中使用axios请求测试反应组件?的主要内容,如果未能解决你的问题,请参考以下文章
使用 useEffect 反应 axios 获取请求而不会导致无限循环