<!用Js模拟C#的Attribute>
执行结果<br>
<textarea rows = cols = id = output></textarea><br>
<br>
调试信息<br>
<textarea rows = cols = id = debug></textarea><br>
<script language=javascript>
/* 特性(Attributes)是一种崭新的声明性信息
我们不仅可以通过特性来定义设计层面的信息
(例如help file URL for documentation)
以及运行时(runtime)信息(例如使XML与class相联系)
而且我们还可以利用特性建立自描述(selfdescribing)组件
*/
function Attribute()//Attribute 基类可以自行定义其中的接口以扩充功能这里只是一个简单的演示因此留空
{
}
function TestMethod() //定义一个新的Attribute类 TestMethod用它来给需要进行单元测试的方法提供额外信息
{
thisname = TestMethod;
}TestMethodprototype = new Attribute();
function TestMethodAttribute() //必需的执行方法
{
return new TestMethod();
}
function DebugOutput(bOutput) //定义一个新的Attribute类 DebugOutput用它来指示是否在测试中输出额外的调试信息
{
thisname = DebugOutput;
thisisAllowDebugOutput = bOutput;
}DebugOutputprototype = new Attribute();
function DebugOutputAttribute(bOutput)//必需的执行方法
{
return new DebugOutput(bOutput);
}
Function__captureAttributes = function(obj)
{
var attributeDef = /\[\w+\]*\n*(?=\=[\s]*function)/g;
var matches = nstructortoString()match(attributeDef);
if(matches != null)
{
for (var i = ; i < matcheslength; i++)
{
var part = matches[i]split(/[\s\n]/);
var attrLists = part[]split();
var methodObj = eval(part[partlength]);
methodObj__attributes = new Array();
methodObj__attributes__all = new Array();
for (var j = ; j < attrListslength; j++)
{
if(!/^+\(*\)$/test(attrLists[j]slice()))
{
attrLists[j] = [ + attrLists[j]slice() + () + ]; //处理省略括号的情况
}
if(!/^+Attribute$/test(attrLists[j]split(()[]))
{
attrLists[j] = attrLists[j]split(()[] + Attribute + ( + attrLists[j]split(()[];
}
var attrObj = eval(eval(attrLists[j])[]);
methodObj__attributes__allpush(attrObj);
methodObj__attributes[attrLists[j]split(()[]replace(/[\[\]]/g)replace(/Attribute$/g)] = attrObj;
methodObj__attributes[attrLists[j]split(()[]replace(/[\[\]]/g)] = attrObj;
}
}
}
}
function UnitTest()//单元测试框架被赋予[TestMethod]特性的方法会被作为Case执行测试
{
thiserrors = ;
thispassed = ;
//声明TestMethod特性testString方法将被runCase方法执行同时声明了DebugOutput特性将返回的信息输出到调试窗口
//特性的声明必须放在被指定特性的方法之前而且要独占一行如果有多个特性可以以逗号分隔
//包含特性声明的函数要以;结尾不可省略
[TestMethod][DebugOutput(true)]
UnitTestprototypetestString = function()//测试字符串方法这里假设自己实现了一个String类然后来测试
{
var testCase = new String();
testCase = abc;
thisTest(testCase == abc);//测试赋值操作
testCase += def;
thisTest(testCase == abcdef); //测试连接操作
thisTest(testCaselength == ); //测试长度属性
selfoutputvalue += \n;
var result = Debug testString finished with + thispassed + cases passed and + thiserrors + cases failed!\n;
thispassed = ;
thiserrors = ;
return result;
};
//只测试不输出调试信息的方法
[TestMethod]
UnitTestprototypetestRegexp = function()
{
var errors = ;
var passed = ;
if(/abc/test(abc))
{
selfoutputvalue += ;
passed ++;
}
else
{
selfoutputvalue += e;
errors ++;
}
if(/abc/test(aababcd))
{
selfoutputvalue += ;
passed ++;
}
};
//不被测试的方法
UnitTestprototypefoo = function()
{
alert(foo not being tested!);
};
UnitTestprototyperunCases = function()
{
for (each in this)
{
if(this[each]__attributes != null && this[each]__attributes[DebugOutput] != null)
{
var result = this[each]call(this);
if(this[each]__attributes[DebugOutput]isAllowDebugOutput)
{
selfdebugvalue = result;
}
}
else if(this[each]__attributes != null && this[each]__attributes[TestMethod] != null)
{
this[each]call(this);
}
}
};
UnitTestprototypeTest = function(cond)
{
if(cond)
{
selfoutputvalue += ;
thispassed ++;
}
else
{
selfoutputvalue += ;
thiserrors ++;
}
};
//在类内部捕获Attribute对象必须在使用特性的对象内部声明这一点同C#还是有区别的
Function__captureAttributes(this);
}
var test = new UnitTest();
testrunCases();
//或许一些人不太习惯上面的这种做法但是它有一个显而易见的好处就是我如果希望添加更多的单元测试用例只需要增加新的标记为[TestMethod]的方法而不用修改runCases方法的任何代码!这样我就可以将整个单元测试框架封装起来而依然允许使用者从外部添加自己的测试方法!
//除此以外我们可以用特性相当便利地用来实现许多模式这方面的具体深入用法这里不再详述了有兴趣的朋友可以自行尝试^^不过现在这个模拟的特性还有一些不足之处例如只能将特性声明到对象方法而不能声明给对象本身这样要实现一些像Serializable之类的对象特性就不太方便了==
</script>