JavaScript单元测试localStorage的核心是隔离环境、模拟行为、验证读写逻辑:用Jest手动mock内存版localStorage,确保测试间互不干扰,并专注测试封装函数的调用正确性、异常处理及边界情况。

JavaScript 中对本地存储(localStorage)操作写单元测试,核心是**隔离真实浏览器环境、模拟存储行为、验证读写逻辑是否符合预期**。由于 localStorage 是全局、有状态的 API,直接在测试中调用会污染测试上下文、导致用例间相互干扰,所以不能直接依赖真实实现。
用 Jest 模拟 localStorage(推荐)
Jest 提供了开箱即用的全局模拟能力,可在测试前重置并控制 localStorage 行为:
- 在测试文件顶部或
setupTests.js中,用jest.mock或手动替换localStorage对象 - 更常用且简洁的方式:直接在每个测试前用
beforeEach清空并重建一个内存版localStorage - 示例实现(Jest):
const createMockStorage = () => {
let store = {};
return {
getItem: jest.fn((key) => store[key] || null),
setItem: jest.fn((key, value) => { store[key] = String(value); }),
removeItem: jest.fn((key) => { delete store[key]; }),
clear: jest.fn(() => { store = {}; }),
key: jest.fn((n) => Object.keys(store)[n]),
length: jest.fn(() => Object.keys(store).length),
};
};
beforeEach(() => {
Object.defineProperty(global, 'localStorage', {
value: createMockStorage(),
});
});
这样每个测试都拿到干净的“内存 localStorage”,互不干扰,且所有调用都被 jest.fn() 记录,方便断言。
测试你封装的存储工具函数
假设你写了类似这样的工具:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
export const saveUser = (user) => {
localStorage.setItem('user', JSON.stringify(user));
};
export const loadUser = () => {
const data = localStorage.getItem('user');
return data ? JSON.parse(data) : null;
};
对应测试可这样写:
- 验证
saveUser是否正确调用setItem,且参数序列化无误 - 验证
loadUser在有值/无值时返回预期结果 - 利用
mockReturnValue控制getItem返回值来覆盖不同场景
test('saveUser calls localStorage.setItem with stringified user', () => {
const user = { id: 1, name: 'Alice' };
saveUser(user);
expect(localStorage.setItem).toHaveBeenCalledWith('user', JSON.stringify(user));
});
test('loadUser returns parsed object when data exists', () => {
localStorage.getItem.mockReturnValue('{"id":2,"name":"Bob"}');
expect(loadUser()).toEqual({ id: 2, name: 'Bob' });
});
test('loadUser returns null when no data', () => {
localStorage.getItem.mockReturnValue(null);
expect(loadUser()).toBeNull();
});
避免直接测试原生 API,专注业务逻辑
不需要也不应该测试 “localStorage.setItem 是否真的存进硬盘”——那是浏览器职责。你要测的是:
- 你的函数是否在合适时机、以合适格式调用了
setItem/getItem - 是否处理了解析失败(如 JSON 无效)、空值、类型边界等异常情况
- 是否按约定键名读写,是否做了防错包装(比如 try-catch 包裹
JSON.parse)
例如,健壮的 loadUser 应该容错:
export const loadUser = () => {
try {
const data = localStorage.getItem('user');
return data ? JSON.parse(data) : null;
} catch (e) {
console.warn('Failed to parse user from localStorage', e);
return null;
}
};
对应测试就要覆盖 JSON.parse 抛错的场景,用 mockImplementation 模拟异常。
注意测试运行环境一致性
确保测试在 Node.js 环境(如 Jest 默认)下执行时,不会因缺少 localStorage 报错;同时也要保证在真实浏览器中(如 Cypress 或 Playwright E2E)能正常工作。关键点:
- 不要在模块顶层直接访问
localStorage(否则 Node 下会报ReferenceError),应封装在函数内延迟执行 - 若需兼容 SSR(服务端渲染),可用
typeof window !== 'undefined'做存在性检查 - 单元测试只关心逻辑分支,不关心 DOM 或持久化效果

















