当想用Jest模拟外部模块时,我们可以使用jest.mock()
方法来自动模拟模块上的功能。
然后我们可以根据需要在模拟模块上操纵和询问模拟功能。
例如,考虑下面的人为模拟axios模块的示例:
import myModuleThatCallsAxios from '../myModule';
import axios from 'axios';
jest.mock('axios');
it('Calls the GET method as expected', async () => {
const expectedResult: string = 'result';
axios.get.mockReturnValueOnce({ data: expectedResult });
const result = await myModuleThatCallsAxios.makeGetRequest();
expect(axios.get).toHaveBeenCalled();
expect(result).toBe(expectedResult);
});
以上内容在Jest中运行正常,但会引发Typescript错误:
类型'(URL:属性'mockReturnValueOnce'不存在 字符串,配置?:AxiosRequestConfig |未定义)=> AxiosPromise'。
axios.get
的typedef正确不包含mockReturnValueOnce
属性。通过将axios.get
包装为Object(axios.get)
,我们可以强制Typescript将Option Explicit
#If VBA7 And Win64 Then
Private Declare PtrSafe Function URLDownloadToFile Lib "urlmon" _
Alias "URLDownloadToFileA" ( _
ByVal pCaller As LongPtr, _
ByVal szURL As String, _
ByVal szFileName As String, _
ByVal dwReserved As LongPtr, _
ByVal lpfnCB As LongPtr _
) As Long
#Else
Private Declare Function URLDownloadToFile Lib "urlmon" _
Alias "URLDownloadToFileA" ( _
ByVal pCaller As Long, _
ByVal szURL As String, _
ByVal szFileName As String, _
ByVal dwReserved As Long, _
ByVal lpfnCB As Long _
) As Long
#End If
Public Const BINDF_GETNEWESTVERSION As Long = &H10
Public Sub GetLinks()
Dim sResponse As String, html As New HTMLDocument
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", "https://sebgroup.lu/private/luxembourg-based-funds/download-of-portfolio-holdings", False
.send
sResponse = StrConv(.responseBody, vbUnicode)
End With
sResponse = Mid$(sResponse, InStr(1, sResponse, "<!DOCTYPE "))
With html
.body.innerHTML = sResponse
Dim list As Object, i As Long
Set list = html.getElementsByClassName("linklist")(0).getElementsByTagName("a")
For i = 0 To list.Length - 1
If instr(list(i).getAttribute("href"),"SEB_") > 0 Then
downloadfile list(i).getAttribute("href")
End If
Next i
End With
End Sub
Public Sub downloadfile(ByVal url As String)
Dim fileName As String, fileNames() As String, folderName As String
fileNames = Split(url, "/")
fileName = fileNames(UBound(fileNames))
folderName = "C:\Users\User\Desktop\CurrentDownloads\" & fileName '<==change as required
Dim ret As Long
ret = URLDownloadToFile(0, url, folderName, BINDF_GETNEWESTVERSION, 0)
End Sub
视为对象文字,但是:
在保持类型安全的同时模仿函数的惯用方式是什么?
答案 0 :(得分:10)
添加此行代码const mockedAxios = axios as jest.Mocked<typeof axios>
。然后使用mockedAxios调用mockReturnValueOnce。
使用您的代码,应该像这样完成:
import myModuleThatCallsAxios from '../myModule';
import axios from 'axios';
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;
it('Calls the GET method as expected', async () => {
const expectedResult: string = 'result';
mockedAxios.get.mockReturnValueOnce({ data: expectedResult });
const result = await myModuleThatCallsAxios.makeGetRequest();
expect(mockedAxios.get).toHaveBeenCalled();
expect(result).toBe(expectedResult);
});
答案 1 :(得分:9)
要在保持类型安全的同时习惯性地模拟该功能,请结合使用spyOn和mockReturnValueOnce:
import myModuleThatCallsAxios from '../myModule';
import axios from 'axios';
it('Calls the GET method as expected', async () => {
const expectedResult: string = 'result';
// set up mock for axios.get
const mock = jest.spyOn(axios, 'get');
mock.mockReturnValueOnce({ data: expectedResult });
const result = await myModuleThatCallsAxios.makeGetRequest();
expect(mock).toHaveBeenCalled();
expect(result).toBe(expectedResult);
// restore axios.get
mock.mockRestore();
});
答案 2 :(得分:7)
请使用ts-jest
中的mocked
功能
import myModuleThatCallsAxios from '../myModule';
import axios from 'axios';
jest.mock('axios');
// OPTION - 1
const mockedAxios = mocked(axios, true)
// your original `it` block
it('Calls the GET method as expected', async () => {
const expectedResult: string = 'result';
mockedAxios.mockReturnValueOnce({ data: expectedResult });
const result = await myModuleThatCallsAxios.makeGetRequest();
expect(mockedAxios.get).toHaveBeenCalled();
expect(result).toBe(expectedResult);
});
// OPTION - 2
// wrap axios in mocked at the place you use
it('Calls the GET method as expected', async () => {
const expectedResult: string = 'result';
mocked(axios).get.mockReturnValueOnce({ data: expectedResult });
const result = await myModuleThatCallsAxios.makeGetRequest();
// notice how axios is wrapped in `mocked` call
expect(mocked(axios).get).toHaveBeenCalled();
expect(result).toBe(expectedResult);
});
我无法强调mocked
有多出色,再也没有类型转换了。
答案 3 :(得分:4)
为导入提供新功能以扩展诸如declare module "axios" { ... }
之类的原始模块的常用方法。这不是最佳选择,因为这应该在整个模块中完成,而模拟可能在一个测试中可用而在另一个测试中不可用。
在这种情况下,类型安全的方法是在需要的地方断言类型:
(axios.get as jest.Mock).mockReturnValueOnce({ data: expectedResult });
...
expect(axios.get as jest.Mock).toHaveBeenCalled();
答案 4 :(得分:0)
@hutabalian当您使用axios.get
或axios.post
时,该代码非常有效,但是如果您使用config
来请求以下代码,则该代码会很好地工作:
const expectedResult: string = 'result';
const mockedAxios = axios as jest.Mocked<typeof axios>;
mockedAxios.mockReturnValueOnce({ data: expectedResult });
将导致此错误:
TS2339(TS)属性'mockReturnValueOnce'在类型上不存在 “嘲笑”。
您可以改为这样解决它:
AxiosRequest.test.tsx
import axios from 'axios';
import { MediaByIdentifier } from '../api/mediaController';
jest.mock('axios', () => jest.fn());
test('Test AxiosRequest',async () => {
const mRes = { status: 200, data: 'fake data' };
(axios as unknown as jest.Mock).mockResolvedValueOnce(mRes);
const mock = await MediaByIdentifier('Test');
expect(mock).toEqual(mRes);
expect(axios).toHaveBeenCalledTimes(1);
});
mediaController.ts:
import { sendRequest } from './request'
import { AxiosPromise } from 'axios'
import { MediaDto } from './../model/typegen/mediaDto';
const path = '/api/media/'
export const MediaByIdentifier = (identifier: string): AxiosPromise<MediaDto> => {
return sendRequest(path + 'MediaByIdentifier?identifier=' + identifier, 'get');
}
request.ts:
import axios, { AxiosPromise, AxiosRequestConfig, Method } from 'axios';
const getConfig = (url: string, method: Method, params?: any, data?: any) => {
const config: AxiosRequestConfig = {
url: url,
method: method,
responseType: 'json',
params: params,
data: data,
headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json' },
}
return config;
}
export const sendRequest = (url: string, method: Method, params?: any, data?: any): AxiosPromise<any> => {
return axios(getConfig(url, method, params, data))
}
答案 5 :(得分:0)
更新到最新的 Axios (0.21.1) 后,我开始遇到这种问题。我尝试了很多解决方案,但都没有结果。
我的解决方法:
type axiosTestResponse = (T: unknown) => Promise<typeof T>;
...
it('some example', async () => {
const axiosObject = {
data: { items: [] },
status: 200,
statusText: 'ok',
headers: '',
config: {},
} as AxiosResponse;
(Axios.get as axiosTestResponse) = () => Promise.resolve(axiosObject);
});