我了解这是jest
的基本功能,并且我应该能够使用文档和其他在线资源来弄清楚,但是我不知何故,因此我深表歉意如果这很简单,则前进。
我正在尝试使用Javascript测试一个函数,该函数使用其他模块以及localStorage
执行一些操作,并且我想对其他模块和对localStorage
的调用进行存根处理。我为Jest找到的文档对于我来说似乎太简单了,无法适应我的用例,例如声明一个mock
然后在测试中调用它-在我的情况下这不会发生,因为我想要的功能我的函数在内部调用了要模拟的对象,我没有将其作为依赖项传入。让我给出一些代码来解释:文件名为dataInLocalStorage.js
import serialize from './serialize'; // simple module that serialises data
import deserialize from './deserialize'; // simple module that deserialises data
import findObject from './findObject'; // find an object in the deserialised data
const addDataToLocalStorage = (data) => {
const dataStored = deserialize(localStorage.getItem('data')); // fetch data from localStorage
const isStored = !!findObject(dataStored, data); // check whether the data I want to store is already there
if (isStored) { return null; } // if data is already stored, skip
const serializedData = serialize(data); // serialise data to be stored
return localStorage.setItem('data', serializedData); // store serialised data in localStorage
};
export { addDataToLocalStorage };
此模块的目的只是以串行化方式将数据存储在localStorage
中,但以累加方式进行,因此添加数据不会删除以前存储的数据,也不会添加重复项。 / p>
无论如何,我的测试文件如下所示:文件名为dataInLocalStorage.test.js
import { addDataToLocalStorage } from '../dataInLocalStorage';
describe('addDataToLocalStorage', () => {
const deserialize = jest.fn();
beforeAll(() => {
localStorage.removeItem('data');
});
const data = {
name: 'johnny'
};
addDataToLocalStorage(data);
it('adds the data to local storage', () => {
expect(deserialize).toHaveBeenCalled();
});
});
这是此尝试的相当令人惊讶的错误。
expect(jest.fn()).toHaveBeenCalled()
Expected mock function to have been called, but it was not called.
17 |
18 | it('adds the data to local storage', () => {
> 19 | expect(deserialize).toHaveBeenCalled();
| ^
20 | });
21 | });
最重要的是,我尝试将deserialize
函数导入测试文件中的位置,并在其中添加jest.mock
,但该方法也不起作用。
请注意,这不是我的代码100%,为了简便起见,我对其进行了修改,以使其更易于阅读,对不起,如果有一些不符之处,我会尽力而为进行转换。
如果您知道要查看的内容,则会发现这显然不起作用。使用其他(更有用的)期望,测试通过了,但是在想法是想模拟它并提供自己的返回值时,在deserialize
文件中添加一些控制台日志表明它仍在运行。
旁注:我来自Ruby on Rails,使用RSpec进行模拟非常简单,而我希望Jest也一样。可能是这样,但是我无法绕开它,因为似乎不可能直接引用我要模拟的功能/模块。在RSpec中,执行allow(MySerializer).to receive(:call).and_return(...)
可以解决问题,而我不必担心在测试期间会调用该模块。
答案 0 :(得分:1)
将deserialize
的值设置为笑话模拟时,您正在更改变量值,而不是设置代码正在使用的引用。为了保持引用,它必须是对象中的值。
要导入对象,可以使用import * as deserialize from "./deserialize";
。
然后,您可以使用deserialize.default = jest.fn()
在引用上设置模拟。
https://codesandbox.io/s/88wlzp6q88
import { useIt } from "./use-default-export";
import * as myfunc from "./default-export-function";
test("use-default-export-function", () => {
expect(useIt()).toEqual("real");
});
test("use-default-export-function with mock", () => {
myfunc.default = jest.fn(() => "unreal");
expect(useIt()).toEqual("unreal");
});
在测试中会..
import { addDataToLocalStorage } from '../dataInLocalStorage';
import * as deserialize from './deserialize';
...
deserialize.default = jest.fn();
备用TS兼容版本。 (实际上,它更干净)。
import { useIt } from "./use-default-export";
import myfunc from "./default-export-function";
jest.mock("./default-export-function", () => jest.fn());
test("use-default-export-function with mock", () => {
useIt();
expect(myfunc).toHaveBeenCalled();
});
每个测试返回/解析不同的值
(需要强制转换为jest.Mock
才能使用jest.fn()
函数)
test("use-default-export-function with mock", () => {
const aFunc = myfunc as jest.Mock;
aFunc.mockResolvedValue("bar");
useIt();
expect(useIt()).resolves.toEqual("bar");
});
test("use-default-export-function with mock 2", () => {
const aFunc = myfunc as jest.Mock;
aFunc.mockReturnValue("foo");
useIt();
expect(useIt()).toEqual("foo");
});