<!
用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)
以及運行時(run
time)信息(例如使XML與class相聯系)
而且我們還可以利用特性建立自描述(self
describing)組件
*/
function Attribute() //Attribute 基類
可以自行定義其中的接口以擴充功能
這裡只是一個簡單的演示
因此留空
{
}
function TestMethod() //定義一個新的Attribute類 TestMethod
用它來給需要進行單元測試的方法提供額外信息
{
this
name =
TestMethod
;
}TestMethod
prototype = new Attribute();
function TestMethodAttribute() //必需的執行方法
{
return new TestMethod();
}
function DebugOutput(bOutput) //定義一個新的Attribute類 DebugOutput
用它來指示是否在測試中輸出額外的調試信息
{
this
name =
DebugOutput
;
this
isAllowDebugOutput = bOutput;
}DebugOutput
prototype = new Attribute();
function DebugOutputAttribute(bOutput) //必需的執行方法
{
return new DebugOutput(bOutput);
}
Function
__captureAttributes = function(obj)
{
var attributeDef = /\[\w+\]
*\n
*(?=\=[\s]*function)/g;
var matches = nstructor
toString()
match(attributeDef);
if(matches != null)
{
for (var i =
; i < matches
length; i++)
{
var part = matches[i]
split(/[\s\n]/);
var attrLists = part[
]
split(
);
var methodObj = eval(part[part
length
]);
methodObj
__attributes = new Array();
methodObj
__attributes
__all = new Array();
for (var j =
; j < attrLists
length; 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
__all
push(attrObj);
methodObj
__attributes[attrLists[j]
split(
(
)[
]
replace(/[\[\]]/g
)
replace(/Attribute$/g
)] = attrObj;
methodObj
__attributes[attrLists[j]
split(
(
)[
]
replace(/[\[\]]/g
)] = attrObj;
}
}
}
}
function UnitTest() //單元測試框架
被賦予[TestMethod]特性的方法會被作為Case執行測試
{
this
errors =
;
this
passed =
;
//聲明TestMethod特性
testString方法將被runCase方法執行
同時聲明了DebugOutput特性
將返回的信息輸出到調試窗口
//特性的聲明必須放在被指定特性的方法之前
而且要獨占一行
如果有多個特性可以以逗號分隔
//包含特性聲明的函數要以
;
結尾
不可省略
[TestMethod]
[DebugOutput(true)]
UnitTest
prototype
testString = function() //測試字符串方法
這裡假設自己實現了一個String類然後來測試
{
var testCase = new String();
testCase =
abc
;
this
Test(testCase ==
abc
); //測試賦值操作
testCase +=
def
;
this
Test(testCase ==
abcdef
); //測試連接操作
this
Test(testCase
length ==
); //測試長度屬性
self
output
value +=
\n
;
var result =
Debug
testString finished with
+ this
passed +
cases passed and
+ this
errors +
cases failed!\n
;
this
passed =
;
this
errors =
;
return result;
};
//只測試不輸出調試信息的方法
[TestMethod]
UnitTest
prototype
testRegexp = function()
{
var errors =
;
var passed =
;
if(/abc/
test(
abc
))
{
self
output
value +=
;
passed ++;
}
else
{
self
output
value +=
e
;
errors ++;
}
if(/abc/
test(
aababcd
))
{
self
output
value +=
;
passed ++;
}
};
//不被測試的方法
UnitTest
prototype
foo = function()
{
alert(
foo not being tested!
);
};
UnitTest
prototype
runCases = 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)
{
self
debug
value = result;
}
}
else if(this[each]
__attributes != null && this[each]
__attributes[
TestMethod
] != null)
{
this[each]
call(this);
}
}
};
UnitTest
prototype
Test = function(cond)
{
if(cond)
{
self
output
value +=
;
this
passed ++;
}
else
{
self
output
value +=
;
this
errors ++;
}
};
//在類內部捕獲Attribute對象
必須在使用特性的對象內部聲明
這一點同C#還是有區別的
Function
__captureAttributes(this);
}
var test = new UnitTest();
test
runCases();
//或許一些人不太習慣上面的這種做法
但是它有一個顯而易見的好處就是我如果希望添加更多的單元測試用例
只需要增加新的標記為[TestMethod]的方法
而不用修改runCases方法的任何代碼!這樣我就可以將整個單元測試框架
封裝起來
而依然允許使用者從
外部
添加自己的測試方法!
//除此以外
我們可以用
特性
相當便利地用來實現許多模式
這方面的具體深入用法這裡不再詳述了
有興趣的朋友可以自行嘗試^^
不過現在這個模擬的
特性
還有一些不足之處
例如只能將特性聲明到對象
方法
而不能聲明給對象本身
這樣要實現一些像Serializable之類的對象特性就不太方便了=
=
</script>
From:http://tw.wingwit.com/Article/program/Java/hx/201311/25602.html