欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript單元測(cè)試ABC

 更新時(shí)間:2012年04月12日 12:07:05   作者:  
在服務(wù)器端的單元測(cè)試中,都有各種各樣的測(cè)試框架,在JavaScript中現(xiàn)在也有一些很優(yōu)秀的框架,但在本文中,我們將自己動(dòng)手一步步來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的單元測(cè)試框架
前言
  當(dāng)前,在軟件開(kāi)發(fā)中單元測(cè)試越來(lái)越受到開(kāi)發(fā)者的重視,它能提高軟件的開(kāi)發(fā)效率,而且能保障開(kāi)發(fā)的質(zhì)量。以往,單元測(cè)試往往多見(jiàn)于服務(wù)端的開(kāi)發(fā)中,但隨著Web編程領(lǐng)域的分工逐漸明細(xì),在前端Javascript開(kāi)發(fā)領(lǐng)域中,也可以進(jìn)行相關(guān)的單元測(cè)試,以保障前端開(kāi)發(fā)的質(zhì)量。
  在服務(wù)器端的單元測(cè)試中,都有各種各樣的測(cè)試框架,在JavaScript中現(xiàn)在也有一些很優(yōu)秀的框架,但在本文中,我們將自己動(dòng)手一步步來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的單元測(cè)試框架。
  JS單元測(cè)試有很多方面,比較多的是對(duì)方法功能檢查,對(duì)瀏覽器兼容性檢查,本文主要談第一種。

本文檢查的JS代碼是我以前寫(xiě)的一個(gè)JS日期格式化的方法,原文在這里(javascript日期格式化函數(shù),跟C#中的使用方法類似),代碼如下:
復(fù)制代碼 代碼如下:

Date.prototype.toString=function(format){
var time={};
time.Year=this.getFullYear();
time.TYear=(""+time.Year).substr(2);
time.Month=this.getMonth()+1;
time.TMonth=time.Month<10?"0"+time.Month:time.Month;
time.Day=this.getDate();
time.TDay=time.Day<10?"0"+time.Day:time.Day;
time.Hour=this.getHours();
time.THour=time.Hour<10?"0"+time.Hour:time.Hour;
time.hour=time.Hour<13?time.Hour:time.Hour-12;
time.Thour=time.hour<10?"0"+time.hour:time.hour;
time.Minute=this.getMinutes();
time.TMinute=time.Minute<10?"0"+time.Minute:time.Minute;
time.Second=this.getSeconds();
time.TSecond=time.Second<10?"0"+time.Second:time.Second;
time.Millisecond=this.getMilliseconds();
var oNumber=time.Millisecond/1000;
if(format!=undefined && format.replace(/\s/g,"").length>0){
format=format
.replace(/yyyy/ig,time.Year)
.replace(/yyy/ig,time.Year)
.replace(/yy/ig,time.TYear)
.replace(/y/ig,time.TYear)
.replace(/MM/g,time.TMonth)
.replace(/M/g,time.Month)
.replace(/dd/ig,time.TDay)
.replace(/d/ig,time.Day)
.replace(/HH/g,time.THour)
.replace(/H/g,time.Hour)
.replace(/hh/g,time.Thour)
.replace(/h/g,time.hour)
.replace(/mm/g,time.TMinute)
.replace(/m/g,time.Minute)
.replace(/ss/ig,time.TSecond)
.replace(/s/ig,time.Second)
.replace(/fff/ig,time.Millisecond)
.replace(/ff/ig,oNumber.toFixed(2)*100)
.replace(/f/ig,oNumber.toFixed(1)*10);
}
else{
format=time.Year+"-"+time.Month+"-"+time.Day+" "+time.Hour+":"+time.Minute+":"+time.Second;
}
return format;
}

這段代碼目前沒(méi)有發(fā)現(xiàn)比較嚴(yán)重的bug,本文為了測(cè)試,我們把 .replace(/MM/g,time.TMonth) 改為 .replace(/MM/g,time.Month),這個(gè)錯(cuò)誤是當(dāng)月份小于10時(shí),沒(méi)有用兩位數(shù)表示月份。
  現(xiàn)在有這么一句話,好的設(shè)計(jì)都是重構(gòu)出來(lái)的,在本文中也一樣,我們從最簡(jiǎn)單的開(kāi)始。
第一版:用最原始的alert
  作為第一版,我們很偷懶的直接用alert來(lái)檢查,完整代碼如下:
復(fù)制代碼 代碼如下:

<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<meta charset="utf-8"/>
</head>
<body>
<script type="text/javascript">
Date.prototype.toString=function(format){
var time={};
time.Year=this.getFullYear();
time.TYear=(""+time.Year).substr(2);
time.Month=this.getMonth()+1;
time.TMonth=time.Month<10?"0"+time.Month:time.Month;
time.Day=this.getDate();
time.TDay=time.Day<10?"0"+time.Day:time.Day;
time.Hour=this.getHours();
time.THour=time.Hour<10?"0"+time.Hour:time.Hour;
time.hour=time.Hour<13?time.Hour:time.Hour-12;
time.Thour=time.hour<10?"0"+time.hour:time.hour;
time.Minute=this.getMinutes();
time.TMinute=time.Minute<10?"0"+time.Minute:time.Minute;
time.Second=this.getSeconds();
time.TSecond=time.Second<10?"0"+time.Second:time.Second;
time.Millisecond=this.getMilliseconds();
var oNumber=time.Millisecond/1000;
if(format!=undefined && format.replace(/\s/g,"").length>0){
format=format
.replace(/yyyy/ig,time.Year)
.replace(/yyy/ig,time.Year)
.replace(/yy/ig,time.TYear)
.replace(/y/ig,time.TYear)
.replace(/MM/g,time.Month)
.replace(/M/g,time.Month)
.replace(/dd/ig,time.TDay)
.replace(/d/ig,time.Day)
.replace(/HH/g,time.THour)
.replace(/H/g,time.Hour)
.replace(/hh/g,time.Thour)
.replace(/h/g,time.hour)
.replace(/mm/g,time.TMinute)
.replace(/m/g,time.Minute)
.replace(/ss/ig,time.TSecond)
.replace(/s/ig,time.Second)
.replace(/fff/ig,time.Millisecond)
.replace(/ff/ig,oNumber.toFixed(2)*100)
.replace(/f/ig,oNumber.toFixed(1)*10);
}
else{
format=time.Year+"-"+time.Month+"-"+time.Day+" "+time.Hour+":"+time.Minute+":"+time.Second;
}
return format;
}
var date=new Date(2012,3,9);
alert(date.toString("yyyy"));
alert(date.toString("MM"));
</script>
</body>
</html>

運(yùn)行后會(huì)彈出 2012 和 4 ,觀察結(jié)果我們知道 date.toString("MM")方法是有問(wèn)題的。
  這種方式很不方便,最大的問(wèn)題是它只彈出了結(jié)果,并沒(méi)有給出正確或錯(cuò)誤的信息,除非對(duì)代碼非常熟悉,否則很難知道彈出的結(jié)果是正是誤,下面,我們寫(xiě)一個(gè)斷言(assert)方法來(lái)進(jìn)行測(cè)試,明確給出是正是誤的信息。
第二版:用assert進(jìn)行檢查
  斷言是表達(dá)程序設(shè)計(jì)人員對(duì)于系統(tǒng)應(yīng)該達(dá)到狀態(tài)的一種預(yù)期,比如有一個(gè)方法用于把兩個(gè)數(shù)字加起來(lái),對(duì)于3+2,我們預(yù)期這個(gè)方法返回的結(jié)果是5,如果確實(shí)返回5那么就通過(guò),否則給出錯(cuò)誤提示。
  斷言是單元測(cè)試的核心,在各種單元測(cè)試的框架中都提供了斷言功能,這里我們寫(xiě)一個(gè)簡(jiǎn)單的斷言(assert)方法:
復(fù)制代碼 代碼如下:

function assert(message,result){
if(!result){
throw new Error(message);
}
return true;
}

這個(gè)方法接受兩個(gè)參數(shù),第一個(gè)是錯(cuò)誤后的提示信息,第二個(gè)是斷言結(jié)果
  用斷言測(cè)試代碼如下:
復(fù)制代碼 代碼如下:

var date=new Date(2012,3,9);
try{
assert("yyyy should return full year",date.toString("yyyy")==="2012");
}catch(e){
alert("Test failed:"+e.message);
}
try{
assert("MM should return full month",date.toString("MM")==="04");
}
catch(e){
alert("Test failed:"+e.message);
}

  運(yùn)行后會(huì)彈出如下窗口:

第三版:進(jìn)行批量測(cè)試

  在第二版中,assert方法可以給出明確的結(jié)果,但如果想進(jìn)行一系列的測(cè)試,每個(gè)測(cè)試都要進(jìn)行異常捕獲,還是不夠方便。另外,在一般的測(cè)試框架中都可以給出成功的個(gè)數(shù),失敗的個(gè)數(shù),及失敗的錯(cuò)誤信息。

  為了可以方便在看到測(cè)試結(jié)果,這里我們把結(jié)果用有顏色的文字顯示的頁(yè)面上,所以這里要寫(xiě)一個(gè)小的輸出方法PrintMessage:
復(fù)制代碼 代碼如下:

function PrintMessage(text,color){
var div=document.createElement("div");
div.innerHTML=text;
div.style.color=color;
document.body.appendChild(div);
delete div;
}

  下面,我們就寫(xiě)一個(gè)類似jsTestDriver中的TestCase方法,來(lái)進(jìn)行批量測(cè)試:
復(fù)制代碼 代碼如下:

function testCase(name,tests){
var successCount=0;
var testCount=0;
for(var test in tests){
testCount++;
try{
tests[test]();
PrintMessage(test+" success","#080");
successCount++;
}
catch(e){
PrintMessage(test+" failed:"+e.message,"#800");
}
}
PrintMessage("Test result: "+testCount+" tests,"+successCount+" success, "+ (testCount-successCount)+" failures","#800");
}

  測(cè)試代碼:
復(fù)制代碼 代碼如下:

var date=new Date(2012,3,9);
testCase("date toString test",{
yyyy:function(){
assert("yyyy should return 2012",date.toString("yyyy")==="2012");
},
MM:function(){
assert("MM should return 04",date.toString("MM")==="04");
},
dd:function(){
assert("dd should return 09",date.toString("dd")==="09");
}
});

  結(jié)果為:

這樣我們一眼就可以看出哪個(gè)出錯(cuò)了。但這樣是否就完美了呢,我們可以看到最后那個(gè)測(cè)試中 var date=new Date(2012,3,9)是放在testCase外面定義的,并且整個(gè)testCase的測(cè)試代碼中共用了date,這里因?yàn)楦鱾€(gè)方法中沒(méi)有對(duì)date的值進(jìn)行修改,所以沒(méi)出問(wèn)題,如果某個(gè)測(cè)試方法中對(duì)date的值修改了呢,測(cè)試的結(jié)果就是不準(zhǔn)確的,所以在很多測(cè)試框架中都提供了setUp和tearDown方法,用來(lái)對(duì)統(tǒng)一提供和銷毀測(cè)試數(shù)據(jù),下面我們就在我們的testCase中加上setUp和tearDown方法。
第四版:統(tǒng)一提供測(cè)試數(shù)據(jù)的批量測(cè)試

  首先我們添加setUp和tearDown方法:
復(fù)制代碼 代碼如下:

testCase("date toString",{
setUp:function(){
this.date=new Date(2012,3,9);
},
tearDown:function(){
delete this.date;
},
yyyy:function(){
assert("yyyy should return 2012",this.date.toString("yyyy")==="2012");
},
MM:function(){
assert("MM should return 04",this.date.toString("MM")==="04");
},
dd:function(){
assert("dd should return 09",this.date.toString("dd")==="09");
}
});

  由于setUp和tearDown方法不參與測(cè)試,所以我們要修改testCase代碼:
復(fù)制代碼 代碼如下:

function testCase(name,tests){
var successCount=0;
var testCount=0;
var hasSetUp=typeof tests.setUp == "function";
var hasTearDown=typeof tests.tearDown == "function";
for(var test in tests){
if(test==="setUp"||test==="tearDown"){
continue;
}
testCount++;
try{
if(hasSetUp){
tests.setUp();
}
tests[test]();
PrintMessage(test+" success","#080");

if(hasTearDown){
tests.tearDown();
}

successCount++;
}
catch(e){
PrintMessage(test+" failed:"+e.message,"#800");
}
}
PrintMessage("Test result: "+testCount+" tests,"+successCount+" success, "+ (testCount-successCount)+" failures","#800");
}

  運(yùn)行后的結(jié)果跟第三版相同。
小結(jié)及參考文章

  上面說(shuō)了,好的設(shè)計(jì)是不斷重構(gòu)的結(jié)果,上面的第四版是不是就完美了呢,遠(yuǎn)遠(yuǎn)沒(méi)有達(dá)到,這里只是一個(gè)示例。如果大家需要這方面的知識(shí),我后面可以再寫(xiě)寫(xiě)各個(gè)測(cè)試框架的使用。

  本文只是JS單元測(cè)試入門(mén)級(jí)的示例,讓初學(xué)者對(duì)JS的單元測(cè)試有個(gè)初步概念,屬于拋磚引玉,歡迎各位高人拍磚補(bǔ)充。

  本文參考了《測(cè)試驅(qū)動(dòng)的JavaScript開(kāi)發(fā)》(個(gè)人覺(jué)得還不錯(cuò),推薦下)一書(shū)第一章,書(shū)中的測(cè)試用例也是一個(gè)時(shí)間函數(shù),不過(guò)寫(xiě)的比較復(fù)雜,初學(xué)者不太容易看懂。
作者:Artwl

相關(guān)文章

  • js類中獲取外部函數(shù)名的方法

    js類中獲取外部函數(shù)名的方法

    js類中獲取外部函數(shù)名的方法...
    2007-08-08
  • JavaScript新增的兩個(gè)原始數(shù)據(jù)類型詳解(Record和Tuple)

    JavaScript新增的兩個(gè)原始數(shù)據(jù)類型詳解(Record和Tuple)

    js中原始數(shù)據(jù)類型有Number、String、Boolean、Null、Undefined、Symbol (ES6引入的數(shù)據(jù)類型),引用的數(shù)據(jù)類型有Object,Array,Function,下面這篇文章主要給大家介紹了關(guān)于JavaScript新增兩個(gè)原始數(shù)據(jù)類型(Record和Tuple)的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • 原生javascript實(shí)現(xiàn)addClass,removeClass,hasClass函數(shù)

    原生javascript實(shí)現(xiàn)addClass,removeClass,hasClass函數(shù)

    這篇文章主要介紹了原生javascript實(shí)現(xiàn)addClass,removeClass,hasClass函數(shù)的相關(guān)代碼,有需要的小伙伴可以參考下
    2016-02-02
  • layui實(shí)現(xiàn)三級(jí)導(dǎo)航菜單

    layui實(shí)現(xiàn)三級(jí)導(dǎo)航菜單

    這篇文章主要為大家詳細(xì)介紹了layui實(shí)現(xiàn)三級(jí)導(dǎo)航菜單,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • javascript獲取URL參數(shù)與參數(shù)值的示例代碼

    javascript獲取URL參數(shù)與參數(shù)值的示例代碼

    本篇文章主要是對(duì)javascript獲取URL參數(shù)與參數(shù)值的示例代碼進(jìn)行了介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助
    2013-12-12
  • JavaScript垃圾回收機(jī)制原理總結(jié)深入探究

    JavaScript垃圾回收機(jī)制原理總結(jié)深入探究

    就像人類會(huì)產(chǎn)生垃圾一樣,程序運(yùn)行過(guò)程中也會(huì)產(chǎn)生垃圾,如果不及時(shí)回收輕則將會(huì)拖慢程序運(yùn)行,重則會(huì)導(dǎo)致系統(tǒng)崩潰,也就是所謂的內(nèi)存泄漏。所以垃圾回收非常必要
    2022-10-10
  • 微信h5靜默和非靜默授權(quán)獲取用戶openId的方法和步驟

    微信h5靜默和非靜默授權(quán)獲取用戶openId的方法和步驟

    這篇文章主要介紹了微信h5靜默和非靜默授權(quán)獲取用戶openId的方法和步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • JavaScript編制留言簿程序代碼

    JavaScript編制留言簿程序代碼

    也許你有一個(gè)很酷的主頁(yè),很希望與人分享。同時(shí),你希望訪問(wèn)你主頁(yè)的人能對(duì)你的主頁(yè)提供一些意見(jiàn)和建議,或者你對(duì)某個(gè)主題感興趣,而希望客人也許能給你一幫助,這就要用到留言簿。留言簿使得你能與每一個(gè)訪問(wèn)你主頁(yè)的人交換信息。
    2008-09-09
  • JavaScript定義函數(shù)的三種實(shí)現(xiàn)方法

    JavaScript定義函數(shù)的三種實(shí)現(xiàn)方法

    這篇文章主要介紹了JavaScript定義函數(shù)的三種實(shí)現(xiàn)方法的相關(guān)資料,希望通過(guò)本文大家能夠掌握三種定義函數(shù)的方法,需要的朋友可以參考下
    2017-09-09
  • JS實(shí)現(xiàn)斐波那契數(shù)列的五種方式(小結(jié))

    JS實(shí)現(xiàn)斐波那契數(shù)列的五種方式(小結(jié))

    這篇文章主要介紹了JS實(shí)現(xiàn)斐波那契數(shù)列的五種方式(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09

最新評(píng)論