Ela*_*ich 9 javascript unit-testing private-methods
例如,在许多框架中,内部函数变量用作私有变量
Raphael = (function(){
var _private = function(a,b) {return a+b;};
var _public = function(a) {return _private(a,a);}
var object = {mult2:_public};
return object;
})();
Run Code Online (Sandbox Code Playgroud)
在这里,我们无法从全局命名空间中访问名为的变量private,因为它是第一行中匿名函数的内部变量.
有时这个函数包含一个大的Javascript框架,因此它不会污染全局命名空间.
我需要在Raphael内部单元测试一些对象用法(在上面的例子中,我希望对对象运行单元测试private).我该如何测试它们?
编辑:我收到了关于应该测试公共接口的单元测试的评论.
我来指一个用例.我正在写一个名为的库Raphael.该库应该只向全局命名空间添加一个名称,仅此而已.这是Javascript的特殊要求,因为Javascript没有名称空间.
假设Raphael使用链表.如果Javascript有包的概念,我会这样做
require 'linked_list'
Raphael = (function(){/* use linked list */})();
Run Code Online (Sandbox Code Playgroud)
但是,Javascript不允许我以任何不会使用链表对象污染全局范围的方式执行此操作!因此,我必须内联linked_list到Raphael的本地范围:
Raphael = (function(){
/* implement linked list */
var linked_list = function(){/*implementation*/};
})();
Run Code Online (Sandbox Code Playgroud)
现在我想测试linked_list实现.
Gar*_*ett 12
你仍然忽略了这一点.
单元测试的要点是验证对象的公共接口是否符合预期.单元测试显示代码的工作原理.
唯一应该测试的是对象的公共接口.这样,当开发人员想要更改对象的实现方式时,您只会担心被测对象是否仍然能够实现预期的对象.
如果你觉得那个闭包里面的对象需要测试,那么测试一下,但是在外部做,然后把它传递给闭包.
var Raphael= function(listIterator) {
listIterator.method();
}(new ListIterator());
Run Code Online (Sandbox Code Playgroud)
虚假黑客,如下所示,是完全不合适的(在单元测试或任何地方).
测试函数应该很简单,只测试一件事,并有一个断言.这通常发生在三到十行测试代码中.
当你到达测试函数复杂的程度时,因为他们将遵循你所询问的方法,然后(1)意识到你的设计可能不是你想要的那样并且改变它以便它是,或(2)改变您对测试的期望.
关于你发布的代码,你忘记了var,错过了分号,并使用了两个保留字作为标识符:private和public.
不使用的结果var是可能触发与非标准GlobalScopePolluter类型对象的各种实现相关的错误和问题("IE不支持此属性或方法"在IE中看到).使用FutureReservedWord的结果是SyntaxError.实现可以提供语法扩展以允许 FutureReservedWord作为标识符,实际上很多都可以,但是最好不要依赖这样的扩展,如果你遇到错误,那将完全是你的错.
您提到过向用户提供代码.我建议你不要那样做,直到你获得更多的经验和理解你正在做的事情.
// DO NOT USE THIS CODE.
var Raphael = (function(){
var _private = function(a,b) {return a+b;};
var _public = function(a) {return _private(a,a);};
var object = {mult2:_public};
return object;
})();
var leakedFunction;
// Spurious hack:
// Give valueOf a side effect of leaking function.
// valueOf is called by the _private function as a
// side effect of primitive conversion, where
// ToPrimitive(input argument, hint Number) results
// in calling valueOf.
function valueOfSnoop(){
leakedFunction = leakedFunction || valueOfSnoop.caller || function(){};
return 2;
}
var a = {
valueOf : valueOfSnoop
};
Raphael.mult2(a, 3);
var privateMathod = leakedFunction;
alert(leakedFunction(1, 2));
Run Code Online (Sandbox Code Playgroud)
该示例代码仅用于证明这样的事情是可能的.鉴于这种选择,它是前面提到的替代品的不良替代品; 要么改变你的设计,要么改变你的测试.
var Raphael;
var test = true; //or false;
Raphael = (function(){
var private = function(a,b) {return a+b;};
var public = function(a) {return private(a,a);}
var object = {mult2:public};
if (test) Raphael.private = private;
return object;
})();
Run Code Online (Sandbox Code Playgroud)