笑话:如何正确模拟节点模块?
Posted
技术标签:
【中文标题】笑话:如何正确模拟节点模块?【英文标题】:Jest: How to correctly mock a node module? 【发布时间】:2018-12-31 17:26:38 【问题描述】:我想用 Jest 在 React Native 中模拟 node_module 'React Native Keychain'。
在docs 之后,我创建了一个名为__mocks__
的文件夹,并在其中创建了一个名为react-native-keychain.js
的文件。
这是文件中的代码:
export default jest.mock("react-native-keychain", () =>
const token = "abcdefghijklmnopqrstuvwxyz0123456789";
const credentials =
username: "session",
password: token
;
return
setGenericPassword: jest.fn(
(username, password) => new Promise((resolve, reject) => resolve(true)) // eslint-disable-line no-unused-vars
),
getGenericPassword: jest.fn(() => new Promise((resolve, reject) => resolve(credentials))), // eslint-disable-line no-unused-vars
resetGenericPassword: jest.fn(() => new Promise((resolve, reject) => resolve(true))) // eslint-disable-line no-unused-vars
;
);
然后我为使用这个库的函数编写了测试:
import * as keyChainFunctions from "react-native-keychain";
import setToken, getToken, clearToken from "./secureStorage";
const token = "abcdefghijklmnopqrstuvwxyz0123456789";
describe("set token", () =>
it("saves the token in the keychain", () =>
expect.assertions(1);
return setToken(token).then(res =>
console.log(res);
console.log(keyChainFunctions);
expect(keyChainFunctions.setGenericPassword).toHaveBeenCalledWith("session", token);
);
);
);
问题是,测试失败了。我收到错误消息:
FAIL app/api/secureStorage/secureStorage.test.js
set token
✕ saves the token in the keychain (42ms)
● set token › saves the token in the keychain
expect(jest.fn())[.not].toHaveBeenCalledWith()
jest.fn() value must be a mock function or spy.
Received: undefined
10 | console.log(res);
11 | console.log(keyChainFunctions);
> 12 | expect(keyChainFunctions.setGenericPassword).toHaveBeenCalledWith("session", token);
| ^
13 | );
14 | );
15 | );
at app/api/secureStorage/secureStorage.test.js:12:52
at tryCallOne (node_modules/promise/lib/core.js:37:12)
at node_modules/promise/lib/core.js:123:15
at flush (node_modules/asap/raw.js:50:29)
● set token › saves the token in the keychain
expect.assertions(1)
Expected one assertion to be called but received zero assertion calls.
6 | describe("set token", () =>
7 | it("saves the token in the keychain", () =>
> 8 | expect.assertions(1);
| ^
9 | return setToken(token).then(res =>
10 | console.log(res);
11 | console.log(keyChainFunctions);
at Object.<anonymous> (app/api/secureStorage/secureStorage.test.js:8:12)
还有console.log()
产量:
console.log app/api/secureStorage/secureStorage.test.js:10
true
console.log app/api/secureStorage/secureStorage.test.js:11
default:
addMatchers: [Function: addMatchers],
advanceTimersByTime: [Function: advanceTimersByTime],
autoMockOff: [Function: disableAutomock],
autoMockOn: [Function: enableAutomock],
clearAllMocks: [Function: clearAllMocks],
clearAllTimers: [Function: clearAllTimers],
deepUnmock: [Function: deepUnmock],
disableAutomock: [Function: disableAutomock],
doMock: [Function: mock],
dontMock: [Function: unmock],
enableAutomock: [Function: enableAutomock],
fn: [Function: bound fn],
genMockFromModule: [Function: genMockFromModule],
isMockFunction: [Function: isMockFunction],
mock: [Function: mock],
requireActual: [Function: bound requireModule],
requireMock: [Function: bound requireMock],
resetAllMocks: [Function: resetAllMocks],
resetModuleRegistry: [Function: resetModules],
resetModules: [Function: resetModules],
restoreAllMocks: [Function: restoreAllMocks],
retryTimes: [Function: retryTimes],
runAllImmediates: [Function: runAllImmediates],
runAllTicks: [Function: runAllTicks],
runAllTimers: [Function: runAllTimers],
runOnlyPendingTimers: [Function: runOnlyPendingTimers],
runTimersToTime: [Function: runTimersToTime],
setMock: [Function: setMock],
setTimeout: [Function: setTimeout],
spyOn: [Function: bound spyOn],
unmock: [Function: unmock],
useFakeTimers: [Function: useFakeTimers],
useRealTimers: [Function: useRealTimers]
这告诉我什么:
1. 模拟工作(因为正确返回 true)或调用来自 React Native Keychain 的实际 setGenericPassword
函数。
2. 出于某种原因,keychainfunctions
被定义为jest.mock
对象,而不是三个模拟函数。
如果模拟有效,感觉 1 和 2 相互矛盾。
我究竟做错了什么?为什么这个模拟不起作用?如何解释这些奇怪的console.log()
s 和失败的测试?
Bamse 在 cmets 中建议仅导出对象。此解决方法有效。我仍然会对如何正确地做到这一点/我做错了什么感兴趣。
const token = "abcdefghijklmnopqrstuvwxyz0123456789";
const credentials =
username: "session",
password: token
;
export const setGenericPassword = jest.fn(
(username, password) => new Promise((resolve, reject) => resolve(true)) // eslint-disable-line no-unused-vars
);
export const getGenericPassword = jest.fn(
() => new Promise((resolve, reject) => resolve(credentials)) // eslint-disable-line no-unused-vars
);
export const resetGenericPassword = jest.fn(() => new Promise((resolve, reject) => resolve(true))); // eslint-disable-line no-unused-vars
【问题讨论】:
这个答案也可能有用:***.com/questions/45617362/… 如果你只想要一个返回值,你可以简单地使用jest.mock(module);
import module from 'module';
module.mockReturnValue(Promise.resolve('response'));
的模块bypass
【参考方案1】:
您可以尝试在测试中使用jest.createMockFromModule 并仅模拟您需要的方法。 (以前在 26 之前的 Jest 版本中称为 genMockFromModule)
希望对你有帮助
【讨论】:
Bamse 不喜欢嘲弄,但无论如何都有帮助。 Lycklig den som har en sådan vän。 :-) 我认为如果在__mocks__/react-native-keychain.js
中您使用您想要的方法导出一个对象,您的模拟也会起作用。目前您正在导出 jest
模拟。 Visibleman 今天早上你让我笑了,让我想起了我的旧漫画书。
我试过这样使用它:const keyChainFunctions = jest.genMockFromModule("react-native-keychain").default;
但它也抛出了同样的错误。
你是对的。只需导出普通对象即可。我在问题中添加了它。以上是关于笑话:如何正确模拟节点模块?的主要内容,如果未能解决你的问题,请参考以下文章