如何在Mocha测试中模拟全局变量(定义,模块,窗口)? [英] How to mock global variables (define, module, window) in mocha tests?
问题描述
为了追求100%的代码覆盖率,我尝试使用mocha来测试我的javascript模块是否在 AMD
, CommonJS/Node
下正确加载,和 browser
条件.我正在使用的模式如下:
In the pursuit of 100% code coverage, I am attempting to use mocha to test that my javascript module is loading correctly under AMD
, CommonJS/Node
, and browser
conditions. The pattern I'm using is below:
my-module.js
(function(global){
function MyClass(){}
// AMD
if(typeof define === 'function' && define.amd){
define(function(){
return MyClass;
});
// CommonJS/Node
} else if (typeof module !== 'undefined' && module.exports){
module.exports = MyClass;
// Browser
} else {
global.MyClass = MyClass;
}
})(this);
由于我正在使用节点运行测试,因此从未定义define
,并且始终定义了module
.因此"CommonJS/Node"条件是唯一经过测试的条件.
Since I am running my tests with node, define
is never defined, and module
is always defined; so the "CommonJS/Node" condition is the only one that ever gets tested.
到目前为止,我尝试过的事情是这样的:
What I have tried so far is something like this:
my-module.test.js
var MyClass = require('./my-module');
describe('MyClass', function(){
// suite of tests for the class itself
// uses 'var instance = new MyClass();' in each test
// all of these tests pass
});
describe('Exports', function(){
// suite of tests for the export portion
beforeEach(function(){
MyClass = null; // will reload module for each test
define = null; // set 'define' to null
module = null; // set 'module' to null
});
// tests for AMD
describe('AMD', function(){
it('should have loaded as AMD module', function(){
var define = function(){};
define.amd = true;
MyClass = require('./my-module'); // might be cached?
// hoping this reloads with 'define' in its parent scope
// but it does not. AMD condition is never reached.
expect(spy).to.have.been.called(); // chai spy, code omitted
});
});
});
我正在使用间谍程序检查define
是否已被调用,但是该模块未显示任何可用的define
重新加载的迹象.我该如何实现?
I'm using spies to check if define
has been called, but the module doesn't show any signs of ever being reloaded with define
available to it. How can I achieve that?
并且有一种安全的方法来取消module
以便我也可以测试浏览器条件吗?
And is there a safe way of nullifying module
so that I can test the browser condition as well?
推荐答案
I was able to create a custom solution (borrowing the majority of this code from http://howtonode.org/testing-private-state-and-mocking-deps)
module-loader.js
此模块基本上会创建一个新的上下文,在该上下文中,您的自定义属性可在与require
和console
等相同的全局空间中使用.
This module basically creates a new context in which your custom properties are available in the same global space as require
and console
, etc.
var vm = require('vm');
var fs = require('fs');
var path = require('path');
var extend = require('extend'); // install from npm
/**
* Helper for unit testing:
* - load module with mocked dependencies
* - allow accessing private state of the module
*
* @param {string} filePath Absolute path to module (file to load)
* @param {Object=} mocks Hash of mocked dependencies
*/
exports.loadModule = function(filePath, mocks) {
mocks = mocks || {};
// this is necessary to allow relative path modules within loaded file
// i.e. requiring ./some inside file /a/b.js needs to be resolved to /a/some
var resolveModule = function(module) {
if (module.charAt(0) !== '.') return module;
return path.resolve(path.dirname(filePath), module);
};
var exports = {};
var context = {
require: function(name) {
return mocks[name] || require(resolveModule(name));
},
console: console,
exports: exports,
module: {
exports: exports
}
};
var extendMe = {};
extend(true, extendMe, context, mocks);
// runs your module in a VM with a new context containing your mocks
// http://nodejs.org/api/vm.html#vm_vm_runinnewcontext_code_sandbox_filename
vm.runInNewContext(fs.readFileSync(filePath), extendMe);
return extendMe;
};
my-module.test.js
var loadModule = require('./module-loader').loadModule;
// ...
it('should load module with mocked global vars', function(){
function mockMethod(str){
console.log("mock: "+str);
}
var MyMockModule = loadModule('./my-module.js', {mock:mockMethod});
// 'MyClass' is available as MyMockModule.module.exports
});
my-module.js
(function(global){
function MyClass(){}
if(typeof mock !== 'undefined'){
mock("testing"); // will log "mock: testing"
}
module.exports = MyClass;
})(this);
这篇关于如何在Mocha测试中模拟全局变量(定义,模块,窗口)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!