日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

JavaScript单元测试ABC

發(fā)布時間:2025/3/13 javascript 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JavaScript单元测试ABC 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

  當前,在軟件開發(fā)中單元測試越來越受到開發(fā)者的重視,它能提高軟件的開發(fā)效率,而且能保障開發(fā)的質(zhì)量。以往,單元測試往往多見于服務(wù)端的開發(fā)中,但隨著Web編程領(lǐng)域的分工逐漸明細,在前端Javascript開發(fā)領(lǐng)域中,也可以進行相關(guān)的單元測試,以保障前端開發(fā)的質(zhì)量。

  在服務(wù)器端的單元測試中,都有各種各樣的測試框架,在JavaScript中現(xiàn)在也有一些很優(yōu)秀的框架,但在本文中,我們將自己動手一步步來實現(xiàn)一個簡單的單元測試框架。

  JS單元測試有很多方面,比較多的是對方法功能檢查,對瀏覽器兼容性檢查,本文主要談第一種。

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

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; }

  這段代碼目前沒有發(fā)現(xiàn)比較嚴重的bug,本文為了測試,我們把?.replace(/MM/g,time.TMonth) 改為?.replace(/MM/g,time.Month),這個錯誤是當月份小于10時,沒有用兩位數(shù)表示月份。

  現(xiàn)在有這么一句話,好的設(shè)計都是重構(gòu)出來的,在本文中也一樣,我們從最簡單的開始。

第一版:用最原始的alert

  作為第一版,我們很偷懶的直接用alert來檢查,完整代碼如下:

<!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>

  運行后會彈出 2012 和 4 ,觀察結(jié)果我們知道 date.toString("MM")方法是有問題的。

  這種方式很不方便,最大的問題是它只彈出了結(jié)果,并沒有給出正確或錯誤的信息,除非對代碼非常熟悉,否則很難知道彈出的結(jié)果是正是誤,下面,我們寫一個斷言(assert)方法來進行測試,明確給出是正是誤的信息。

第二版:用assert進行檢查

  斷言是表達程序設(shè)計人員對于系統(tǒng)應(yīng)該達到狀態(tài)的一種預(yù)期,比如有一個方法用于把兩個數(shù)字加起來,對于3+2,我們預(yù)期這個方法返回的結(jié)果是5,如果確實返回5那么就通過,否則給出錯誤提示。

  斷言是單元測試的核心,在各種單元測試的框架中都提供了斷言功能,這里我們寫一個簡單的斷言(assert)方法:

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

  這個方法接受兩個參數(shù),第一個是錯誤后的提示信息,第二個是斷言結(jié)果

  用斷言測試代碼如下:

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); }

  運行后會彈出如下窗口:

第三版:進行批量測試

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

  為了可以方便在看到測試結(jié)果,這里我們把結(jié)果用有顏色的文字顯示的頁面上,所以這里要寫一個小的輸出方法PrintMessage:

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

  下面,我們就寫一個類似jsTestDriver中的TestCase方法,來進行批量測試:

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"); }

  測試代碼:

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é)果為:

  這樣我們一眼就可以看出哪個出錯了。但這樣是否就完美了呢,我們可以看到最后那個測試中 var date=new Date(2012,3,9)是放在testCase外面定義的,并且整個testCase的測試代碼中共用了date,這里因為各個方法中沒有對date的值進行修改,所以沒出問題,如果某個測試方法中對date的值修改了呢,測試的結(jié)果就是不準確的,所以在很多測試框架中都提供了setUp和tearDown方法,用來對統(tǒng)一提供和銷毀測試數(shù)據(jù),下面我們就在我們的testCase中加上setUp和tearDown方法。

第四版:統(tǒng)一提供測試數(shù)據(jù)的批量測試

  首先我們添加setUp和tearDown方法:

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方法不參與測試,所以我們要修改testCase代碼:

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"); }

  運行后的結(jié)果跟第三版相同。

小結(jié)及參考文章

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

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

  本文參考了《測試驅(qū)動的JavaScript開發(fā)》(個人覺得還不錯,推薦下)一書第一章,書中的測試用例也是一個時間函數(shù),不過寫的比較復(fù)雜,初學(xué)者不太容易看懂。

轉(zhuǎn)載于:https://www.cnblogs.com/artwl/archive/2012/04/09/2439049.html

總結(jié)

以上是生活随笔為你收集整理的JavaScript单元测试ABC的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。