如何在Jest中模拟可调用对象?附Kubernetes-Client示例问题
问题:Kubernetes Client Jest 模拟同时支持两种调用方式失败
业务代码中client.api.v1.namespaces存在两种合法调用方式:
- 作为对象调用:
client.api.v1.namespaces.post(namespaceJson) - 作为函数调用:
client.api.v1.namespaces(namespaceName).get()
但当前Jest模拟代码将namespaces设为函数后,调用post方法时会提示“不是函数”,导致测试失败。
业务代码
console.log(`Trying to create a namespace: ${namespaceName}`) try { await client.api.v1.namespaces(namespaceName).get() } catch (err) { try { await client.api.v1.namespaces.post(namespaceJson) } catch (err) { console.log('Error creating namespace: ' + err) return new Promise(function (resolve, reject) { reject(new Error(`Failure creating namespace: ${namespaceName}: ${err}`)) }) } // ... }
原测试代码
jest.doMock('kubernetes-client', () => { const aRejection = jest.fn(() => { const err = new Error(404) err.response = 'Not found' err.status = 404 err.statusCode = 404 return Promise.reject(err) }) const aPromise = jest.fn(() => { return Promise.resolve({ body: { data: { username: 'dXNlcm5hbWUK' // 'username', base64-encoded } } }) }) const namespaces = jest.fn().mockReturnValue({ get: aRejection, post: aPromise }) const mockClient = { api: { v1: { namespaces } }, } return { Client: jest.fn(() => mockClient), } })
解决方法
在JavaScript中,函数本身也是对象,直接给namespaces函数对象添加post方法,就能让它同时支持函数调用和对象属性访问:
修改测试代码中的namespaces定义部分:
const namespaces = jest.fn().mockReturnValue({ get: aRejection }) // 给函数对象添加post方法,对应对象调用的场景 namespaces.post = aPromise
完整修改后的测试代码:
jest.doMock('kubernetes-client', () => { const aRejection = jest.fn(() => { const err = new Error(404) err.response = 'Not found' err.status = 404 err.statusCode = 404 return Promise.reject(err) }) const aPromise = jest.fn(() => { return Promise.resolve({ body: { data: { username: 'dXNlcm5hbWUK' // 'username', base64-encoded } } }) }) const namespaces = jest.fn().mockReturnValue({ get: aRejection }) // 新增:给namespaces函数添加post方法 namespaces.post = aPromise const mockClient = { api: { v1: { namespaces } }, } return { Client: jest.fn(() => mockClient), } })
这样设置后:
- 执行
client.api.v1.namespaces(namespaceName).get()时,namespaces作为函数调用,返回带有get方法的对象,触发aRejection逻辑; - 执行
client.api.v1.namespaces.post(namespaceJson)时,直接调用namespaces函数对象上的post方法,触发aPromise逻辑,不会再出现“post不是函数”的错误。
内容的提问来源于stack exchange,提问作者Resisty
相关产品推荐
相关产品推荐

