我在Javascript中使用模块模式将我的公共接口与私有实现分开。为了简化我正在做的事情,我的代码生成了一个图表。该图表由多个部分(轴,标签,图,图例等)组成。我的代码如下:
var Graph = function() {
var private_data;
function draw_legend() { ... }
function draw_plot() { ... }
function helper_func() { ... }
...
return {
add_data: function(data) {
private_data = data;
},
draw: function() {
draw_legend()
draw_plot()
}
}
}
有些人主张只测试你的类的公共接口,这是有道理的,但我真的想进行一些测试来分别测试每个组件。如果我搞砸了我的draw_legend()函数,我希望测试失败,而不是公共draw()函数的测试。我在这里错了吗?
我可以将不同类中的每个组件分开,例如创建一个Legend类。但是,为有时只有5到10行代码创建一个类似乎很愚蠢,而且它会更加丑陋,因为我需要传递一堆私有状态。而且我无法测试我的助手功能。我还应该这样做吗?我应该吸吮它,只测试公共抽奖()吗?还是有其他解决方案吗?
答案 0 :(得分:9)
无法从外部作用域访问内部函数(私有)。如果要测试内部函数,可以考虑添加公共方法以仅用于测试目的。如果您正在使用某种构建环境,例如ant,您可以预处理javascript文件以进行生产并删除这些测试函数。
实际上Javascript是面向对象的语言。它不是一个属于类型的。
答案 1 :(得分:5)
我的解决方案只是一点点破解。 QUnit示例:
在Qunit测试html的顶部我声明了:
var TEST_AVAILABLE = true;
在可测试类中,我有一个这样的片段:
if(TEST_AVAILABLE){
this.test={
hasDraft:hasDraft,
isInterpIdIn:isInterpIdIn,
// other private methods
};
}
在QUnit中你可以验证
test( "hello booth", function() {
var b = new Booth();
ok(b);
ok(b.test);
ok(!b.test.hasDraft());
});
答案 2 :(得分:3)
我有类似的问题。我提出的解决方案不是我喜欢的,但是它完成了工作并且找不到更好的解决方案。
function Graph()
{
this.Test = function _Test(expressionStr) { return eval(expressionStr); }
var private_data;
function draw_legend() { ... }
function draw_plot() { ... }
function helper_func() { ... }
...
}
测试:
var g = new Graph();
g.Test("helper_func()") == something;
g.Test("private_data") == something2
答案 3 :(得分:1)
实际上有一种简单的方法。您可以使用ajax加载脚本并注入一个公开私有函数的函数。我有一个使用qUnit和jQuery的示例here。但我确信使用纯Javascript可以轻松完成同样的工作。
答案 4 :(得分:0)
在面向对象语言中,您通常会通过让测试类继承其正在测试的类来对受保护的方法进行单元测试。
当然,Javascript实际上并不是面向对象的语言,而且这种模式不允许继承。
我认为你要么公开你的方法,要么放弃对它们进行单元测试。
答案 5 :(得分:0)
只有一个正确的选项:用于测试和生产的不同构建
1)仅标记开发部分
/* test-code */
api._foo = foo
/* end-test-code */
2)稍后将它们剥离......;)
grunt.registerTask("deploy",
[
"concat",
"strip-code",
...
@philwalton撰写了精彩的文章: