使用 jest typescript 模拟 Axios 的类型
Posted
技术标签:
【中文标题】使用 jest typescript 模拟 Axios 的类型【英文标题】:Type of Axios mock using jest typescript 【发布时间】:2018-12-18 21:38:41 【问题描述】:我在一个类中有以下方法:
import axios from 'axios'
public async getData()
const resp = await axios.get(Endpoints.DATA.URL)
return resp.data
然后我正在尝试设置一个 Jest 测试来执行此操作:
jest.mock('axios')
it('make api call to get data', () =>
component.getData()
expect(axios.get).toHaveBeenCalledWith(Endpoints.DATA.URL)
)
问题是因为我没有模拟返回值,所以它给resp.data
一个错误,因为我在null
或undefined
对象上调用data
。我花了至少 2 个小时尝试各种方法来使其正常工作,但我找不到一种方法可以模拟 axios.get
并返回一些值。
Jest 的文档使用 javascript,所以他们给出了这个示例 axios.get.mockResolvedValue(resp)
,但我不能调用 mockResolvedValue
,因为 TypeScript 中的 axios.get
上不存在该方法。
另外,如果你知道除了 Jest 之外的其他优秀的 React 测试库,可以轻松地为 TypeScript 做这些事情,请随时分享。
【问题讨论】:
【参考方案1】:在文件开头:
import axios from 'axios';
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;
现在你可以像往常一样使用它了:
mockedAxios.get.mockRejectedValue('Network error: Something went wrong');
mockedAxios.get.mockResolvedValue( data: );
【讨论】:
我做了完全相同的事情,但是打字稿将此错误归咎于我的 data: null :error TS2345: Argument of type ' data: null; ' is not assignable to parameter of type '(<T = any>(url: string, config?: AxiosRequestConfig | undefined) => AxiosPromise<T>) | PromiseLike<(<T = any>(url: string, config?: AxiosRequestConfig | undefined) => AxiosPromise<T>)>'.
不知道为什么它不起作用...
您可以尝试输入或制作任何内容: data: null as any
【参考方案2】:
如果您想将jest.mock
与"no-any"
一起使用,请尝试以下操作:
import axios, AxiosStatic from 'axios'
interface AxiosMock extends AxiosStatic
mockResolvedValue: Function
mockRejectedValue: Function
jest.mock('axios')
const mockAxios = axios as AxiosMock
it('make api call to get data', () =>
// call this first
mockAxios.mockResolvedValue(yourValue)
component.getData()
expect(mockAxios.get).toHaveBeenCalledWith(Endpoints.DATA.URL)
)
【讨论】:
这有效,不需要其他库,应该接受答案 这种方法也适用于我,无需添加新库。我唯一有点卡住的是如何制作它,这样我就不必在不同的测试文件中重复相同的代码..会调查它并更新评论(希望如此)【参考方案3】:这是我个人经常使用的。
import axios from 'axios';
jest.mock('axios')
it('...', () =>
(axios.get as jest.Mock).mockImplementationOnce(() => Promise.resolve());
// test here
expect(axios.get).toHaveBeenCalled()
【讨论】:
【参考方案4】:但我不能调用 mockResolvedValue,因为 TypeScript 中的 axios.get 上不存在该方法
你可以使用断言:
(axios.get as any).mockResolvedValue(resp)
【讨论】:
项目有一个ts-lint规则"no-any": true
在前一行添加一个 tslint 忽略
1.随着项目的增长和添加更多异步调用,这不会是理想的。 2. 我使用 TypeScript 是因为它强大的类型系统,我不想绕过它。【参考方案5】:
我一直遇到is not a function
问题。如果接受的答案对您不起作用,请尝试使用大写字母 A 导入 axios
即。 Axios
.
import Axios from 'axios';
jest.mock('Axios');
const mockedAxios = Axios as jest.Mocked<typeof Axios>;
【讨论】:
【参考方案6】:我使用sinon
库npm install sinon @types/sinon --save-dev
找到了一个简洁的解决方案。
那么测试代码就变成了:
let component: Component
let axiosStub: SinonStub
beforeAll(() =>
component = new Component()
axiosStub = sinon.stub(axios, 'get')
)
afterAll(() =>
axiosStub.restore()
)
it('make api call to get data', async () =>
// set up behavior
axiosStub.withArgs(Endpoints.DATA.URL).returns(data: [])
// method under test
const res = await component.getData()
// assertions
expect(res).toEqual([])
)
【讨论】:
【参考方案7】:另一种选择是使用jest.spyOn:
import axios from "axios";
jest.spyOn(axios, "get").mockImplementation(() => Promise.resolve(data: []));
这还为您提供了可以测试的模拟方法的好处,例如:
import axios from "axios";
// ...
const mockedGet = jest
.spyOn(axios, "get")
.mockImplementation(() => Promise.resolve(data: []));
// ...
expect(mockedGet).toBeCalledWith('https://example.api?q=abc&k=123');
【讨论】:
【参考方案8】:从 Jest 24.9.0
开始,这是正确输入 axios
和 Jest 属性的方式。
我们希望类型化的模拟是模拟对象类型包含模拟对象类型和 Jest 模拟类型的联合。据我所知,目前的答案都不能做到这一点。
jest.MockedFunction
jest.MockedClass
import axios from 'axios';
jest.mock('axios');
const mockedAxios = axios as jest.MockedFunction<typeof axios>;
mockedAxios.mockResolvedValue( status: 200, data: 'mockResponse' );
// Or:
(mockedAxios.get as jest.MockedFunction<typeof mockedAxios.get>).mockResolvedValue('mockResponse');
如您所见,您可以手动转换您需要的内容,或者您需要一些东西来遍历所有 axios 属性/方法来键入所有内容。
为此(深度模拟类型),您可以使用 Jest 中引入的 jest.mocked() 27.4.0
import axios from 'axios';
jest.mock('axios');
const mockedAxios = jest.mocked(axios, true);
mockedAxios.mockImplementation() // correctly typed
mockedAxios.get.mockImplementation() // also correctly typed
【讨论】:
以上是关于使用 jest typescript 模拟 Axios 的类型的主要内容,如果未能解决你的问题,请参考以下文章
使用 Typescript 从 Jest 手动模拟中导入函数
使用正确类型使用 Jest 和 Typescript 模拟 Express 请求
使用 jest typescript 模拟 Axios 的类型