如何在 Chai 的单元测试中使用 localStorage
How to use localStorage in unit tests with Chai
我有一个带有 React 和 Redux 的应用程序。我的测试引擎是 - Chai
在我的减速器(src/my_reducer.js)中,我尝试像这样从 localStorage 获取令牌:
const initialState = {
profile: {},
token: window.localStorage.getItem('id_token') ? window.localStorage.getItem('id_token') : null,
}
在我的测试文件中 (test/reducer_spec.js) 我在测试用例之前导入了 'my_reducer':
import myReducer from '../src/my_reducer'
我有一个错误,如果我尝试 运行 测试 - localStorage(或 window.localStorage) - 未定义。
我需要模拟 localStorage 吗?如果我需要,它的位置在哪里?
出于测试目的,我建议不要进行任何可能有副作用的调用或在声明中调用外部模块。
因为要求/导入你的减速器隐式调用 window.localStorage.getItem(...)
干净的测试变得困难。
我建议用 init
方法包装您的初始化代码,这样如果您在调用 init
之前 require/import 您的模块,则不会发生任何事情。然后你可以使用 beforeEach
afterEach
来干净地设置 mocks/sandboxes.
import myReducer from '../src/my_reducer'
describe('with faked localStorage', function() {
var sandbox
beforeEach(function() {
sandbox = sinon.sandbox.create()
// fake window.localStorage
})
afterEach(function() {
sandbox.restore()
})
describe('the reducer', function() {
before(function() {
myReducer.init()
})
})
})
第二个最佳解决方案是推迟导入并在 before
测试挂钩中使用 require
。
describe('with fake localStorage', function() {
var sandbox
beforeEach(function() {
sandbox = sinon.sandbox.create()
// fake window.localStorage
})
afterEach(function() {
sandbox.restore()
})
describe('the reducer', function() {
var myReducer
before(function() {
myReducer = require('../src/my_reducer')
})
})
})
那是因为你不是浏览器环境下的运行 Chai。
尝试:
// Make sure there is a window object available, and that it has localstorage (old browsers don't)
const initialState = {
profile: {},
// window.localStorage.getItem('id_token') will return null if key not found
token: window && window.localStorage ? window.localStorage.getItem('id_token') : null,
}
我用 mock-local-storage 解决了问题
我的 运行 测试命令是:
mocha -r mock-local-storage --compilers js:babel-core/register --recursive
我猜你是 运行用 mocha 进行测试?
mocha 在 node.js 中测试 运行,而 node.js 没有全局 window 变量。但是您可以轻松地在测试中创建一个:
global.window = {};
您甚至可以立即将 localStorage 添加到其中:
global.window = { localStorage: /* your mock localStorage */ }
模拟取决于您存储在本地存储中的内容,但对于上面的示例代码,这可能是一个合理的模拟对象:
var mockLocalStorage = {
getItem: function (key) {
if( key === 'id_token' ){ return /* a token object */; }
return null;
}
}
当然,对于不同的测试你可以有不同的模拟,例如另一个模拟可能总是 return null
来测试找不到密钥的情况。
我有一个带有 React 和 Redux 的应用程序。我的测试引擎是 - Chai
在我的减速器(src/my_reducer.js)中,我尝试像这样从 localStorage 获取令牌:
const initialState = {
profile: {},
token: window.localStorage.getItem('id_token') ? window.localStorage.getItem('id_token') : null,
}
在我的测试文件中 (test/reducer_spec.js) 我在测试用例之前导入了 'my_reducer':
import myReducer from '../src/my_reducer'
我有一个错误,如果我尝试 运行 测试 - localStorage(或 window.localStorage) - 未定义。
我需要模拟 localStorage 吗?如果我需要,它的位置在哪里?
出于测试目的,我建议不要进行任何可能有副作用的调用或在声明中调用外部模块。
因为要求/导入你的减速器隐式调用 window.localStorage.getItem(...)
干净的测试变得困难。
我建议用 init
方法包装您的初始化代码,这样如果您在调用 init
之前 require/import 您的模块,则不会发生任何事情。然后你可以使用 beforeEach
afterEach
来干净地设置 mocks/sandboxes.
import myReducer from '../src/my_reducer'
describe('with faked localStorage', function() {
var sandbox
beforeEach(function() {
sandbox = sinon.sandbox.create()
// fake window.localStorage
})
afterEach(function() {
sandbox.restore()
})
describe('the reducer', function() {
before(function() {
myReducer.init()
})
})
})
第二个最佳解决方案是推迟导入并在 before
测试挂钩中使用 require
。
describe('with fake localStorage', function() {
var sandbox
beforeEach(function() {
sandbox = sinon.sandbox.create()
// fake window.localStorage
})
afterEach(function() {
sandbox.restore()
})
describe('the reducer', function() {
var myReducer
before(function() {
myReducer = require('../src/my_reducer')
})
})
})
那是因为你不是浏览器环境下的运行 Chai。
尝试:
// Make sure there is a window object available, and that it has localstorage (old browsers don't)
const initialState = {
profile: {},
// window.localStorage.getItem('id_token') will return null if key not found
token: window && window.localStorage ? window.localStorage.getItem('id_token') : null,
}
我用 mock-local-storage 解决了问题 我的 运行 测试命令是:
mocha -r mock-local-storage --compilers js:babel-core/register --recursive
我猜你是 运行用 mocha 进行测试? mocha 在 node.js 中测试 运行,而 node.js 没有全局 window 变量。但是您可以轻松地在测试中创建一个:
global.window = {};
您甚至可以立即将 localStorage 添加到其中:
global.window = { localStorage: /* your mock localStorage */ }
模拟取决于您存储在本地存储中的内容,但对于上面的示例代码,这可能是一个合理的模拟对象:
var mockLocalStorage = {
getItem: function (key) {
if( key === 'id_token' ){ return /* a token object */; }
return null;
}
}
当然,对于不同的测试你可以有不同的模拟,例如另一个模拟可能总是 return null
来测试找不到密钥的情况。