独立于web浏览器的JavaScript单元测试

独立于web浏览器的JavaScript单元测试,javascript,node.js,unit-testing,travis-ci,Javascript,Node.js,Unit Testing,Travis Ci,我有客户端JavaScript,它不会以任何方式与DOM或web浏览器交互。我想在Travis CI中对这段代码的功能进行单元测试(这只是一个奇特的数据库/缓冲区),而无需启动web浏览器。命令行JavaScript让我觉得我需要node.js。我浏览了各种单元测试库,并决定使用Mocha,因为它简单,但是使用基于node.js的库测试基于浏览器的模块/类似乎过于困难 具体来说,我想测试这个(简化的)浏览器JavaScript有效代码: // I need this NameSpace to o

我有客户端JavaScript,它不会以任何方式与DOM或web浏览器交互。我想在Travis CI中对这段代码的功能进行单元测试(这只是一个奇特的数据库/缓冲区),而无需启动web浏览器。命令行JavaScript让我觉得我需要node.js。我浏览了各种单元测试库,并决定使用Mocha,因为它简单,但是使用基于node.js的库测试基于浏览器的模块/类似乎过于困难

具体来说,我想测试这个(简化的)浏览器JavaScript有效代码:

// I need this NameSpace to organise my code and isolate from other code
var Nengo = {};

Nengo.DataStore = function(dims) {
    this.times = [];
    this.data = [];
    for (var i=0; i < dims; i++) {
        this.data.push([]);
    }
}

Nengo.DataStore.prototype.push = function(row) {
    this.times.push(row[0]);
    for(var i = 0; i < this.data.length; i++){
        this.data[i].push(row[i+1]);
    }
}
它失败,出现以下错误:

/home/saubin/javascript_test/test/simple_test.js:5
    var data_store = new Nengo.DataStore(2);
                     ^
ReferenceError: Nengo is not defined
    at Suite.<anonymous> (/home/saubin/javascript_test/test/simple_test.js:5:22)
    at context.describe.context.context (/usr/local/lib/node_modules/mocha/lib/interfaces/bdd.js:49:10)
    at Object.<anonymous> (/home/saubin/javascript_test/test/simple_test.js:4:1)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at /usr/local/lib/node_modules/mocha/lib/mocha.js:192:27
    at Array.forEach (native)
    at Mocha.loadFiles (/usr/local/lib/node_modules/mocha/lib/mocha.js:189:14)
    at Mocha.run (/usr/local/lib/node_modules/mocha/lib/mocha.js:422:31)
    at Object.<anonymous> (/usr/local/lib/node_modules/mocha/bin/_mocha:398:16)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:935:3
/home/saubin/javascript\u test/test/simple\u test.js:5
var数据存储=新的Nengo.数据存储(2);
^
ReferenceError:未定义Nengo
在套房。(/home/saubin/javascript_test/test/simple_test.js:5:22)
位于context.descripe.context.context(/usr/local/lib/node_modules/mocha/lib/interfaces/bdd.js:49:10)
反对。(/home/saubin/javascript_test/test/simple_test.js:4:1)
在模块处编译(Module.js:456:26)
在Object.Module.\u extensions..js(Module.js:474:10)
在Module.load(Module.js:356:32)
在Function.Module.\u加载(Module.js:312:12)
at Module.require(Module.js:364:17)
根据需要(模块js:380:17)
at/usr/local/lib/node_modules/mocha/lib/mocha.js:192:27
at Array.forEach(本机)
在Mocha.loadFiles(/usr/local/lib/node_modules/Mocha/lib/Mocha.js:189:14)
在Mocha.run(/usr/local/lib/node_modules/Mocha/lib/Mocha.js:422:31)
反对。(/usr/local/lib/node_modules/mocha/bin/_mocha:398:16)
在模块处编译(Module.js:456:26)
在Object.Module.\u extensions..js(Module.js:474:10)
在Module.load(Module.js:356:32)
在Function.Module.\u加载(Module.js:312:12)
位于Function.Module.runMain(Module.js:497:10)
启动时(node.js:119:16)
在node.js:935:3
解决这个问题的一种方法是放弃节点,将测试结果输出到无头浏览器的DOM中,并获得结果,但这似乎是一个很大的开销。我可以更改代码的结构以与Node.js兼容吗?由于缺乏这方面的知识,还有其他解决方案我没有看到吗?

您可以让代码“node.js感知”,这样它就可以将全局定义放入实际的全局上下文中,同时仍然与浏览器环境完全兼容:

if (typeof window !== "undefined") {
    // in browser, define global to be an alias for window
    // so global can be used to refer to the global namespace in
    // both the browser and node.js
    var global = window;
}

global.Nengo = {};

(function() {
    var Nengo = global.Nengo;

    Nengo.DataStore = function(dims) {
        this.times = [];
        this.data = [];
        for (var i=0; i < dims; i++) {
            this.data.push([]);
        }
    }

    Nengo.DataStore.prototype.push = function(row) {
        this.times.push(row[0]);
        this.data.push(row.slice(1));
    }
})();
if(窗口类型!=“未定义”){
//在浏览器中,将“全局”定义为窗口的别名
//因此,可以使用global来引用中的全局命名空间
//浏览器和node.js
var全局=窗口;
}
global.Nengo={};
(功能(){
var Nengo=global.Nengo;
Nengo.DataStore=函数(dims){
this.times=[];
这个.data=[];
对于(变量i=0;i

然后,请记住,任何全局定义都必须显式地分配给
global
名称空间。在node.js中,这将把它们分配到node.js中的实际
global
命名空间。在浏览器中,这将把它们分配给
窗口
对象,该对象是浏览器中的全局名称空间。

尽管@jfrieen00的答案在技术上是正确的,但我后来提出了另一个答案

首先,我需要重构JavaScript代码,在
数据存储
文件之外声明我的命名空间。然后我将Nengo全局变量声明为jfriend00 descriptions
global.Nengo={},但仅在我的Mocha测试文件中


这样,当我在web浏览器和单元测试中运行时,我的代码将按预期进行测试。

Nengo是否作为节点模块存在?如何加载它?它不是一个节点模块,因为它只在客户端浏览器中运行,根据我的理解,它是一个实际的节点模块,我必须在服务器端运行它。我正在按上面的代码所示加载它,主要是因为我不知道如何加载它。@DaveNewton在我上一篇评论中忘了提到你,所以库只在客户端运行,节点只在服务器端运行。。。这样发送不会很好,不是吗?@DaveNewton是的,我意识到Node.js!=JavaScript。然而,它们的单元测试框架似乎是相同的,所以这让我感到困惑。我可以在命令行中测试客户端JavaScript代码吗?或者我必须使用浏览器吗?您在我的代码中添加闭包有什么特殊原因吗?@Seanny123-只是为了保存一些键入,以便我可以定义一个名为
Nengo
的局部变量,该变量可以像以前一样使用。如果要为每个方法定义键入
global.Nengo.Datastore=function(){…}
,则不需要闭包。
if (typeof window !== "undefined") {
    // in browser, define global to be an alias for window
    // so global can be used to refer to the global namespace in
    // both the browser and node.js
    var global = window;
}

global.Nengo = {};

(function() {
    var Nengo = global.Nengo;

    Nengo.DataStore = function(dims) {
        this.times = [];
        this.data = [];
        for (var i=0; i < dims; i++) {
            this.data.push([]);
        }
    }

    Nengo.DataStore.prototype.push = function(row) {
        this.times.push(row[0]);
        this.data.push(row.slice(1));
    }
})();