[英]How to mock global variables (define, module, window) in mocha tests?
在追求100%代碼覆蓋率的過程中,我試圖使用mocha來測試我的javascript模塊是否在AMD
, CommonJS/Node
和browser
條件下正確加載。 我正在使用的模式如下:
我-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);
由於我使用node運行測試,因此從未定義define
,並且始終定義module
; 所以“CommonJS / Node”條件是唯一一個經過測試的條件。
到目前為止我嘗試的是這樣的:
我-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
可用的跡象。 我怎樣才能做到這一點?
是否有一種安全的方法來取消module
以便我也可以測試瀏覽器條件?
您可能想要查看重新布線模塊。 我不是百分百肯定,但我認為它會讓你做你需要的。
我能夠創建一個自定義解決方案(從http://howtonode.org/testing-private-state-and-mocking-deps借用大部分代碼)
模塊loader.js
此模塊基本上創建了一個新的上下文,您可以在與require
和console
等相同的全局空間中使用自定義屬性。
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;
};
我-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
});
我-module.js
(function(global){
function MyClass(){}
if(typeof mock !== 'undefined'){
mock("testing"); // will log "mock: testing"
}
module.exports = MyClass;
})(this);
這是一個適合我的輕量級解決方案:
let document = (typeof document === "undefined") ? {} : document;
不幸的是,這必須放在正在測試的文件中,對於使用更多document
功能的情況來說會很麻煩,並且對於需要未定義某些內容的測試用例沒有幫助。 但對於簡單的情況,這是一個簡單的解決方案。
(當我發現這個問題時,這是我正在尋找的答案)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.