<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問 http://qaseven.github.io/

    關(guān)于工作效率的心得分享

     這是去年11月底在小組里分享過的工作效率心得,在這里也跟大家分享一下工作“快”感哈哈。我相信大家應(yīng)該都有過工作效率的些許煩惱。而這個(gè)效率啊伴隨我很長時(shí)間的痛苦。每每到PDI的時(shí)候領(lǐng)導(dǎo)必提效率有木有?自認(rèn)為快是不算的,必須領(lǐng)導(dǎo)和客戶方說了算,對(duì)于當(dāng)年校招進(jìn)來的毛驢,是一件淚崩漫長的提升過程。整天琢磨如何快,多快的速度才算快,恨不得快到連參照物都變得動(dòng)感模糊。時(shí)間是把殺豬刀,不僅催人老還得與它賽跑,經(jīng)過這幾年的自殘式磨練,也早該總結(jié)總結(jié)。
      一、 懂得整理需求
      效率是先把重要的事情優(yōu)先排序來完成,好的整理習(xí)慣是可以提高效率的。當(dāng)需求很多的時(shí)候是可以通過整理需求有條不紊的進(jìn)行。只要了解哪些是重要和緊急的事情,就能輕松的決定先處理什么。這個(gè)相當(dāng)于是做項(xiàng)目管理的事情,要善于管理自己的工作。建議學(xué)習(xí)佐藤可士和的《整理術(shù)》。
      例如:本周產(chǎn)品經(jīng)理們提了很多需求:@#¥……&%……&%……
      可這樣做:
      1、列出所有需求
      ABCBBD
      2、歸納類型
      ABBBCD
      3、了解份量
      A(傳輸功能設(shè)計(jì)):總辦需求
      BBB(圖標(biāo)類設(shè)計(jì)): 迭代需求,排一起繪制
      C(新增界面設(shè)計(jì)): 迭代需求,需較多時(shí)間設(shè)計(jì)
      D(功能宣傳圖):迭代需求,版本發(fā)布的新功能宣傳
      4、明確期限
      假如級(jí)別為High、Mid、Low…
      A(傳輸功能設(shè)計(jì)):總辦需求—非常緊急(今天)—High
      D(功能宣傳圖):迭代需求,版本發(fā)布的新功能宣傳—周三—Mid
      C(新增界面設(shè)計(jì)): 迭代需求,需較多時(shí)間設(shè)計(jì)—本周—Mid
      BBB(圖標(biāo)類設(shè)計(jì)): 迭代需求,需較多時(shí)間設(shè)計(jì)—本周—Low
      需求從散到整,從大到小,從繁到簡,從緊急到迭代這樣去處理就會(huì)變得清晰可觀。
      二、要有探究需求真相的精神
      可能很多人也曾拿到需求就馬上畫稿,孰不知是不斷重來的經(jīng)歷。表面應(yīng)付需求是無法解決問題的,要先了解用戶或老板的核心訴求,找出訴求的背后真相,才能夠有合適的方案去解決,才能快刀斬亂麻。本質(zhì)問題得到解決便不會(huì)有重復(fù)工作量而拖延了本來的交付期限。還有就是有一些需求根本不是需求,比如老板只是隨便幾個(gè)建議。所以要思于前,行于后。
      三、練好刀工才能游刃有余
      技能的熟練會(huì)提升工作效率。就像切土豆絲,要切成厚薄、細(xì)條一致又要快,那是必須有一雙好刀手。做圖也一樣,就像畫圖標(biāo),要好質(zhì)量的呈現(xiàn),你明確了所有要注意的細(xì)節(jié),繪制的時(shí)候會(huì)非常快速準(zhǔn)確的完成,一步到位。要使車子走得快,就得給輪子勤上油。
      四、在高速重復(fù)工作中提取模版
      模型套用會(huì)提升工作效率。在工作中一定會(huì)有很多重復(fù)式工作,比如標(biāo)注規(guī)范和切圖這樣必不可少但卻繁瑣沒營養(yǎng)的工作,可以提取模型工具去套用快速完成。規(guī)范標(biāo)注,可以根據(jù)同類窗口、內(nèi)容統(tǒng)一規(guī)范而不要再差異設(shè)計(jì)和重復(fù)標(biāo)注。切圖可以利用軟件工具輸出,比如slicy或PS插件,這是要善于把所有圖標(biāo)控件整理成庫,規(guī)范好命名,便可一鍵批量切圖。還有比如tips彈窗界面,根據(jù)目前所有情況,做典型1~2個(gè)模版,其他直接套用,之后可不再經(jīng)過設(shè)計(jì),開發(fā)根據(jù)模版直接實(shí)現(xiàn)。
    五、學(xué)會(huì)聚焦與屏蔽
      1)專心致志做事
      2)屏蔽干擾消息
      早上應(yīng)該是比較難聚焦做事情的時(shí)間段,到辦公室第一件事往往不是開始工作。比如沒睡醒,各種早上新聞,查看昨天消息等。工作時(shí)被很多信息干擾,群消息,郵件,微信,彈窗廣告等,包括自己有事沒事的逛微博、各路網(wǎng)站,很容易被外界風(fēng)吹草動(dòng)的影響而分心,一天班下來才發(fā)現(xiàn)其實(shí)本應(yīng)該上午就可以完成的工作,還得加班或干脆拖到明天。這都是懶惰病和拖延病,得治。所以要先學(xué)會(huì)屏蔽雜七八,然后全身心聚焦到工作的內(nèi)容里,最后你會(huì)發(fā)現(xiàn)提前完成了很多工作。聚焦利于把需求思考得深一些,把工作做得精細(xì)些,得出的加分項(xiàng)就是完成的質(zhì)量隨高。
      六、多任務(wù)處理
      能夠有全神貫注的狀態(tài),也能夠有“一心多用”的功能。這個(gè)要求比較高,我也好難描述。拿一個(gè)婦女做例子,她可以一邊炒菜一邊看管在旁邊玩耍的孩子,一邊打電話給閨蜜聊去哪里逛街和去哪里美甲,所以女人是一心多用的高手,靈活性非常高。我也常是一心多用的處理我非常繁多且接踵而來的任務(wù),不然總覺得時(shí)間不夠用,或者為了省下后面的事情做些自己想做的事,比如思考、總結(jié),或不用加班。但是建議在做非常繁多、零碎又不需要深度思考的需求時(shí)可以使用這招。最好不要持續(xù)這樣高度緊張的一心多用,長期只會(huì)感覺越來越累,而且打亂節(jié)奏,所以要懂得變化各種技巧。
      七、敏捷響應(yīng)
      緊急需求時(shí),能夠快速響應(yīng),敏捷處理。這個(gè)時(shí)候是最能影響客戶方的感受。還有一些幾乎每天都會(huì)有的臨時(shí)小小需求和bug,只要是合理的,就去免討論部分,快速輸出也是可以的。有一次解決的小需求從修改到輸出給產(chǎn)品只花了28秒,帥呆了自己驚呆了客戶,這就是在日常中慢慢積累的效率好評(píng)。
      八、拍板與結(jié)論的必要性
      1)需要一個(gè)有力決策的人
      2)控制范圍并迅速得出結(jié)論
      一個(gè)有力決策的人可以提高工作效率。由于評(píng)審層級(jí)關(guān)系的復(fù)雜流程,需求確認(rèn)要漫長時(shí)間是家常便飯,所以如果有機(jī)會(huì)碰到老大們都在一起,有些事情能抓住時(shí)機(jī)溝通和拍定的機(jī)會(huì)就迅速做。但不一定老大拍板這個(gè)事情就一定是對(duì)的,有些復(fù)雜的事情安排在會(huì)議上拿出來大家討論,但是一定要有靠譜結(jié)論,如果沒有意識(shí)的控制,沒完沒了的討論就是低效率,要善于控制范圍、節(jié)奏又能迅速總結(jié)的人,能提高解決問題的效率。
      九、當(dāng)自己的事情做
      只有當(dāng)作是自己的事情做,意愿才會(huì)更強(qiáng),而且也會(huì)有一些自己的想法,想著這件事情是有自己的成績?cè)诶锩娴模蜁?huì)更有動(dòng)力。換位思考,當(dāng)作是鍛煉的機(jī)會(huì)。
      十、保持健康和清醒
      健康的身體狀態(tài),健康的作息,健康的工作頻率是效率的革命前提。關(guān)于清醒的辦事用歌德的一句話:在今天和明天之間,有一段很長的時(shí)間,趁你還有精神的時(shí)候,學(xué)習(xí)迅速地辦事。
      總結(jié):
      效率是由綜合因素影響的,但跟個(gè)人辦事風(fēng)格有很大關(guān)系。其實(shí)效率是可以量化,也可進(jìn)階式自我考察,比如接手一個(gè)界面風(fēng)格設(shè)計(jì)從要花1個(gè)月,到半個(gè)月、1周、兩天就可以完成;碼一周代碼變成1天就可碼完。這就能看到效率的有效提升。前兩年長期搭檔的幾位即通產(chǎn)品經(jīng)理,給我封了個(gè)快刀手稱號(hào),開發(fā)也說我以快著稱,才慢慢發(fā)現(xiàn)自己這方面的成長與進(jìn)步。希望這點(diǎn)經(jīng)驗(yàn)總結(jié)能夠給新人帶來幫助,終極祝福永不改稿永不加班!

    posted @ 2014-07-15 10:14 順其自然EVO 閱讀(161) | 評(píng)論 (0)編輯 收藏

    如何考查自己的測試水平?

      提問:如何考評(píng)自己的測試水平
      回答:個(gè)人認(rèn)為可以通過如下幾項(xiàng)進(jìn)行綜合考評(píng):
      1.通過自己編寫的測試用例發(fā)現(xiàn)的有效bug數(shù)
      可以考評(píng)的是測試人員編寫測試用例的水平(編寫測試用例屬于測試人員的工作職責(zé)范疇)。當(dāng)然此項(xiàng)并不一定能證明測試人員水平,還與開發(fā)人員能力有關(guān),如果開發(fā)人員代碼寫的好,測試人員測試出來的bug自然就少。所以需要用多個(gè)項(xiàng)目進(jìn)行考評(píng)
      2.在項(xiàng)目中測試的總的有效bug數(shù)量
      同上測試的bug多,并不一定能證明測試人員水平,還與開發(fā)人員能力有關(guān),如果開發(fā)人員代碼寫的好,測試人員測試出來的bug自然就少。所以需要用多個(gè)項(xiàng)目進(jìn)行考評(píng)
      3.漏測率
      計(jì)算公式:客戶反饋的Bug數(shù) / Bug總數(shù)(測試+客戶) *100%
      可以使用多個(gè)指標(biāo)進(jìn)行衡量,如以下幾點(diǎn):
      1)用例包括而未發(fā)現(xiàn)的bug數(shù)/用例總數(shù) (衡量用例執(zhí)行質(zhì)量,執(zhí)行人員的測試效果)
      2)版本交付后又發(fā)現(xiàn)的bug數(shù)/項(xiàng)目bug總數(shù)(衡量總體測試效果,也是重要的產(chǎn)品質(zhì)量,項(xiàng)目質(zhì)量指標(biāo))
      3)用例不包括而發(fā)現(xiàn)的bug數(shù)/bug總數(shù) (衡量用例質(zhì)量)
      4)嚴(yán)重bug在測試周期的分布(后期嚴(yán)重bug比例較重,則顯然整個(gè)項(xiàng)目組都比較被動(dòng),雖然bug最終被發(fā)現(xiàn)了,但仍是一種“漏測”行為)
      值得說明的是
      1)上述指標(biāo)異常并非只是測試人員的責(zé)任,開發(fā)人員也可能會(huì)在后期引入嚴(yán)重缺陷。
      2)測試用例不包括而發(fā)現(xiàn)的bug,一般不認(rèn)為是測試失誤,而是測試用例設(shè)計(jì)和評(píng)審的失誤。
      3)測試用例包括而未被發(fā)現(xiàn)的bug,測試人員應(yīng)付全責(zé)。
      4.對(duì)bug的分析和排查水平
      能從表面現(xiàn)象發(fā)現(xiàn)內(nèi)部結(jié)構(gòu)和規(guī)律,能夠快速準(zhǔn)確地對(duì)bug進(jìn)行定位;
      5.對(duì)軟件測試基礎(chǔ)理論與技術(shù)的了解程度
      首先是精通各種黑盒測試技術(shù),能夠進(jìn)行測試用例設(shè)計(jì)、測試執(zhí)行、編寫缺陷報(bào)告;
      其次是熟悉軟件測試流程和測試過程管理,能夠編寫測試計(jì)劃,具備組織測試工作的能力;
      還有熟悉白盒測試技術(shù),能夠手工或利用相關(guān)工具進(jìn)行單元測試
      6.能否能夠勝任白盒測試、 自動(dòng)化測試性能測試
      7.對(duì)缺陷管理工具、自動(dòng)化測試工具等等的使用程度
      8.是否會(huì)搭建數(shù)據(jù)庫
      目前大部分應(yīng)用軟件都離不開數(shù)據(jù)庫,熟練掌握SQL Server、Oracle、DB2等一種或多種數(shù)據(jù)庫系統(tǒng)的使用,是否會(huì)搭建數(shù)據(jù)庫取決于測試人員是否能夠熟悉使用SQL語言
      9.對(duì)WindowsLinux、Unix等大型主流操作系統(tǒng)的使用和應(yīng)用開發(fā)是否能夠熟練掌握,包括一些網(wǎng)絡(luò)的基礎(chǔ)知識(shí)。
      只有熟練掌握Windows、Linux、Unix等大型主流操作系統(tǒng)的使用和應(yīng)用開發(fā),才具備快速進(jìn)行應(yīng)用系統(tǒng)部署和測試環(huán)境以及網(wǎng)絡(luò)的搭建。
      10.是否善于對(duì)軟件質(zhì)量的分析和對(duì)測試過程進(jìn)行度量,以及編寫軟件質(zhì)量報(bào)告和測試分析報(bào)告的能力等等。

    posted @ 2014-07-15 10:12 順其自然EVO 閱讀(199) | 評(píng)論 (0)編輯 收藏

    Java基本類型與對(duì)象類型的區(qū)別導(dǎo)致的Bug剖析

    本文中所提到的基本類型是指類似 int,long等,而對(duì)象類型是指Integer,Long等。
      基本類型和對(duì)象類型第一個(gè)最大的不同在于初始化的值不同。int 初始化為0,Integer 為null。在一個(gè)線上產(chǎn)品故障的排查過程中發(fā)現(xiàn)根本原因在于開發(fā)同學(xué)把數(shù)據(jù)庫DO對(duì)象的一個(gè)字段從int 改成了Integer引起的,因?yàn)閕nt 類型可以正常的初始化,而Integer 對(duì)象的時(shí)候不能正常插入,導(dǎo)致了線上產(chǎn)品故障。
      正是由于初始化的值的不同,也導(dǎo)致了在進(jìn)行邏輯比較的時(shí)候,對(duì)象類型很容易出現(xiàn)空指針異常:
      基本類型可以直接進(jìn)行邏輯判斷:
    int num;
    if( num >0 ){
    //todo
    }
      這樣的代碼不會(huì)有空指針的異常,但是如果是如下代碼:
    Integer num;
    if( num >0 ){
    //todo
    }
      就會(huì)有空指針異常。這種異常特別容易出現(xiàn)在web的參數(shù)處理上:
      例如:
    public class MyTest {
    @Autowired     private HttpServletResponse response;
    public void execute(@Param("pageSize") Integer pageSize) throws Exception {
    //todo
    //這里容易空指針異常
    if( pageSize<=0 ){
    pageSize = 1;
    }
    //todo
    }
    }
      第二個(gè)不同在于基本類型沒有可執(zhí)行的方法,而對(duì)象類型支持很多封裝的方法,例如Integer 對(duì)象 可以使用toString()的方法。
      第三個(gè)不同在于基本類型不能作為List或者M(jìn)ap的類型,例如:
      List<int>  numList = new ArrayList<int>();  //這樣是不可以的。

    posted @ 2014-07-15 10:10 順其自然EVO 閱讀(139) | 評(píng)論 (0)編輯 收藏

    解讀分布式對(duì)象存儲(chǔ)系統(tǒng)Sheepdog性能測試

      Sheepdog是一個(gè)分布式對(duì)象存儲(chǔ)系統(tǒng),專為虛擬機(jī)提供塊存儲(chǔ),號(hào)稱無單點(diǎn)、零配置、可線性擴(kuò)展(省略更多優(yōu)點(diǎn)介紹)。本文主要關(guān)注其性能究竟如何,測試版本為目前的最新穩(wěn)定版0.7.4。
      測試環(huán)境
      節(jié)點(diǎn)數(shù)量:6個(gè)
      磁盤:各節(jié)點(diǎn)都配備7200轉(zhuǎn)SATA硬盤,型號(hào)WDC WD10EZEX-22RKKA0,容量為1TB,另外測試節(jié)點(diǎn)(即用于啟動(dòng)虛擬客戶機(jī)的宿主機(jī))多配置一塊SSD硬盤,型號(hào)INTEL SSDSA2CW300G3,容量為300GB
      網(wǎng)絡(luò):測試節(jié)點(diǎn)配備PCI-E雙千兆網(wǎng)卡,通過bonding進(jìn)行負(fù)載均衡
      文件系統(tǒng):ext4fs,掛載參數(shù):rw,noatime,barrier=0,user_xattr,data=writeback
      sheepdog集群
      可用空間:6個(gè)節(jié)點(diǎn)各分配100GB,總共600GB
      對(duì)象副本數(shù)量:3個(gè),客戶機(jī)實(shí)際最大可用空間為200GB,接近項(xiàng)目規(guī)劃的容量
      對(duì)象緩存:使用SSD硬盤,分配256GB,可完全緩存客戶機(jī)文件系統(tǒng),隨測試項(xiàng)目需要掛載或卸載
      虛擬客戶機(jī)
      資源:4GB內(nèi)存,4個(gè)邏輯CPU
      使用qemu 1.7啟動(dòng),支持KVM加速、virtio
      兩大測試項(xiàng)目
      IOPS:主要考察較小數(shù)據(jù)塊隨機(jī)讀和寫的能力,測試工具fio(sudo apt-get install fio),測試文件固定為150GB
      吞吐量:主要考察較大數(shù)據(jù)塊順序讀或者寫的能力,測試工具iozone(sudo apt-get install iozone3),測試文件從64MB倍數(shù)遞增到4GB,如沒有特別說明,測試結(jié)果取自操作512MB的數(shù)據(jù)文件
      除特別說明,qemu啟動(dòng)虛擬客戶機(jī)命令如下:
      qemu-system-x86_64 --enable-kvm -m 4096 -smp 4 -drive file=sheepdog:mint,if=virtio,index=0 \ -drive file=sheepdog:data,if=virtio,index=1 -net nic,model=virtio -net user -vnc :1 -daemonize
      IOPS測試
      測試須知
      關(guān)于SATA硬盤的IOPS
      測試用的普通7200轉(zhuǎn)SATA硬盤,官方公布其平均尋道時(shí)間10.5毫秒,所以,根據(jù)以下公式,理論上的IOPS值最多只有65。
      實(shí)測結(jié)果,在單線程同步IO的情況下(下圖深藍(lán)線),也是65,在多任務(wù)(紫線)或者使用異步IO(黃線)的情況下,由于操作系統(tǒng)IO調(diào)度,IOPS能夠達(dá)到80到100之間。如果進(jìn)行讀寫操作的文件遠(yuǎn)遠(yuǎn)小于SATA磁盤大小,縮小了存儲(chǔ)單元尋址范圍,減少了全磁盤尋道時(shí)間,也能提高IOPS,例如,測試文件大小占磁盤大小的1/8的時(shí)候,IOPS最高在90左右(淺藍(lán)線)。
      關(guān)于SSD硬盤的IOPS
      測試用的SSD硬盤,在單線程同步IO的情況下,IOPS最多能夠達(dá)到9000左右(下圖深藍(lán)線),在多任務(wù)(紫線)或者異步IO(黃線)的情況下,最多能夠達(dá)到40000-50000之間。由于構(gòu)造原理不同于傳統(tǒng)磁盤,減小測試文件大小并不能明顯提高IOPS。
      關(guān)于讀寫比例
      由于大多數(shù)業(yè)務(wù)場景既有讀操作,也有寫操作,而且一般讀操作比寫操作多很多,因此,讀寫混合測試項(xiàng)目中的讀寫比例設(shè)定為4:1。一般業(yè)務(wù)很少有完全隨機(jī)寫的情況,因此不進(jìn)行只寫測試。

    關(guān)于電梯算法
      虛擬的客戶機(jī)操作系統(tǒng)的IO調(diào)度算法使用noop,網(wǎng)上有資料能夠提高IOPS,但是實(shí)測效果不明顯,因此最終報(bào)告并沒有把它單列出來。
      IOPS測試1:不使用對(duì)象緩存,只讀測試
      單線程同步IO的情況下(下圖深藍(lán)線),sheepdog的IOPS差不多達(dá)到100,比單節(jié)點(diǎn)單SATA硬盤高,究其原因:客戶機(jī)中的測試文件為150GB,共有三個(gè)副本,即共占450GB,集群有6個(gè)節(jié)點(diǎn),平均每個(gè)節(jié)點(diǎn)75GB,而各個(gè)節(jié)點(diǎn)所在磁盤容量為1TB,僅占其1/13,因此,無其它IO任務(wù)的情況下,IOPS會(huì)比全磁盤隨機(jī)操作高。
      減少客戶機(jī)的測試文件大小為原來的1/8,即19GB,IOPS能夠達(dá)到130-140左右,驗(yàn)證了無其它IO任務(wù)的情況下,測試文件越小,IOPS越高(淺藍(lán)線)。
      恢復(fù)客戶機(jī)的測試文件為150GB,在多任務(wù)(線程數(shù)量為10,紫線)或者異步IO(隊(duì)列深度為10,黃線)的情況下,IOPS可達(dá)230-250。
      250左右是否該sheepdog集群的極限?進(jìn)一步換其它numjob和iodepth的組合進(jìn)行測試,答案是肯定的,測試結(jié)果都在250左右,以下是線程數(shù)量為8,異步IO隊(duì)列深度分別為1、4、16、64、256的測試結(jié)果,線程數(shù)量增加到16,測試數(shù)據(jù)并沒有提高。
      IOPS測試2:使用對(duì)象緩存,只讀測試
      單線程同步IO、使用對(duì)象緩存且緩存命中率100%的情況下(下圖藍(lán)線),sheepdog的IOPS最高可達(dá)6000,對(duì)比相同條件下SSD硬盤的測試結(jié)果(最高9000),還是有些損耗。
      通過多任務(wù)(紫線)或者異步IO(黃線)的方式提高并發(fā)IO數(shù)量,在緩存命中率100%的情況下,IOPS可以提高到40000-50000,基本與相同條件下SSD硬盤的測試結(jié)果相當(dāng)。
      注意上圖為對(duì)數(shù)刻度,且沒有數(shù)據(jù)值,很難比較數(shù)值大小,下圖省略了一半數(shù)據(jù)塊,但是標(biāo)上了數(shù)據(jù)值。
      之所以強(qiáng)調(diào)緩存命中率,是因?yàn)樵诓煌耆芯彺娴臅r(shí)候,IOPS下降很厲害,低于80%的話,可能還不如沒有對(duì)象緩存。下圖是sheepdog對(duì)象緩存命中率與IOPS的關(guān)系圖,其中,測試的數(shù)據(jù)塊大小從512B倍數(shù)遞增到512KB,緩存命中率是在測試過程中,根據(jù)sheepdog的cache目錄中已有的對(duì)象文件數(shù)量估算的平均值,IOPS值是讀取數(shù)據(jù)塊操作在估算的緩存命中率條件下測量的平均值。
      50000是否該sheepdog集群的極限?仿照上面的方法進(jìn)行測試,答案也是肯定的,測試結(jié)果都在50000以內(nèi),以下是線程數(shù)量為8,異步IO隊(duì)列深度分別為1、4、16、64、256的測試結(jié)果,線程數(shù)量增加到16,測試數(shù)據(jù)并沒有提高。
      IOPS測試3:不使用對(duì)象緩存,讀寫混合測試
      讀寫混合測試的IOPS比只讀測試的結(jié)果,總的來說要低一些,而且起伏較大,需要多次測試計(jì)算其平均值。
      單線程同步IO的情況下(下圖深藍(lán)線),能夠達(dá)到80-100。
      減少客戶機(jī)的測試文件大小為原來的1/8,即19GB,IOPS能夠達(dá)到100-120(淺藍(lán)線)。
      恢復(fù)客戶機(jī)的測試文件為150GB,在多任務(wù)(線程數(shù)量為10,紫線)或者異步IO(隊(duì)列深度為10,黃線)的情況下,IOPS大多在180-250之間,但也有時(shí)候只到160左右。
      IOPS測試4:使用對(duì)象緩存,讀寫混合測試
      單線程同步IO、使用對(duì)象緩存且緩存命中率100%的情況下,IOPS差不多達(dá)到4000。
      通過多任務(wù)或者異步IO的方式提高并發(fā)IO數(shù)量,在緩存命中率100%的情況下,IOPS可達(dá)10000-20000之間。
      注意上圖為對(duì)數(shù)刻度,且沒有數(shù)據(jù)值,下圖省略了一半數(shù)據(jù)塊,但是標(biāo)上了數(shù)據(jù)值。可以看到,大數(shù)據(jù)塊讀寫混合的情況下,多任務(wù)或異步IO的IOPS可能還不如單任務(wù)同步IO

    吞吐量測試
      測試須知
      關(guān)于SATA硬盤的吞吐量
      普通7200轉(zhuǎn)SATA硬盤的吞吐量數(shù)據(jù),對(duì)比一下后面SSD硬盤的吞吐量數(shù)據(jù),說明傳統(tǒng)磁盤順序讀寫的能力還是相當(dāng)出色的。
      關(guān)于SSD硬盤的吞吐量
      大數(shù)據(jù)塊(512KB以上)順序讀,吞吐量可達(dá)250MB/s-270MB/s,順序?qū)懀掏铝靠蛇_(dá)200MB/s-210MB/s。
      小數(shù)據(jù)塊(16KB)順序讀,吞吐量也有140MB/s,順序?qū)懘蟾?20MB/s-130MB/s。
      無優(yōu)化sheepdog的吞吐量
      在軟硬件不做任何優(yōu)化的情況下(不綁定雙網(wǎng)卡、不使用virtio、以默認(rèn)參數(shù)啟動(dòng)sheepdog),sheepdog的吞吐量數(shù)據(jù)比較低:
      順序?qū)?/div>
      數(shù)據(jù)塊大小為16KB,吞吐量13-14MB/s
      數(shù)據(jù)塊大小在256KB-4MB之間,吞吐量30-35MB/s
      順序讀
      數(shù)據(jù)塊大小為16KB,吞吐量25MB/s左右,如果數(shù)據(jù)文件大小超過可用內(nèi)存,降低到20MB/s
      數(shù)據(jù)塊大小在512KB-4MB之間,吞吐量125-140MB/s,如果數(shù)據(jù)文件大小超過可用內(nèi)存,降低到80MB/s以下
      以下兩圖,上圖為數(shù)據(jù)文件512MB的測試數(shù)據(jù),下圖為數(shù)據(jù)文件4GB的測試數(shù)據(jù)
      注,不使用virtio方式啟動(dòng)sheepdog的命令行參數(shù)為:
      qemu-system-x86_64 --enable-kvm -m 4096 -smp 4 -drive file=sheepdog:mint,index=0 \ -drive file=sheepdog:data,index=1 -vnc :1 -daemonize
      吞吐量測試1:不使用對(duì)象緩存
      從測試結(jié)果看,使用virtio方式啟動(dòng)客戶機(jī)有利有弊:
      提高了中小數(shù)據(jù)塊讀寫操作的吞吐量
      當(dāng)數(shù)據(jù)塊大小在16KB-512KB之間時(shí),順序讀的吞吐量提高10MB/s-30MB/s不等
      當(dāng)數(shù)據(jù)塊大小在16KB-256KB之間時(shí),順序?qū)懙耐掏铝刻岣?MB/s-8MB/s不等
      大大降低了超大數(shù)據(jù)塊讀操作的吞吐量,至于為何virtio在這種情況下會(huì)降低測試的吞吐量,尚不清楚
      當(dāng)數(shù)據(jù)塊大小達(dá)到2MB或者4MB時(shí),順序讀的吞吐量降低80MB/s-90MB/s
      以下兩圖,上圖為512MB下的測試數(shù)據(jù),下圖為該情況下,與無優(yōu)化sheepdog讀寫512MB數(shù)據(jù)文件兩者吞吐量之差。
      吞吐量測試2:使用對(duì)象緩存
      使用了對(duì)象緩存,順序讀寫的吞吐量與數(shù)據(jù)文件大小沒有直接關(guān)系,即使數(shù)據(jù)文件大小超過可用內(nèi)存。
      同時(shí)也使用了virtio,并沒有因此降低讀取大數(shù)據(jù)塊的吞吐量。
      由于SSD硬盤的特點(diǎn),數(shù)據(jù)塊越大,吞吐量越高,在數(shù)據(jù)塊大小為4MB的情況下,順序讀的吞吐量可達(dá)240MB/s,順序?qū)懸灿?30MB/s;如果數(shù)據(jù)塊大小只有16KB,順序讀和順序?qū)懙耐掏铝糠謩e只有55MB/s和35MB/s。
      總結(jié)sheepdog性能
      以上為sheepdog集群節(jié)點(diǎn)數(shù)為6個(gè),且各節(jié)點(diǎn)都只掛載一塊SATA硬盤的情況下測得的結(jié)果,如果增加集群節(jié)點(diǎn)數(shù),并且每個(gè)節(jié)點(diǎn)都掛滿硬盤,IOPS應(yīng)該會(huì)更高,而吞吐量取決于緩存和網(wǎng)絡(luò)帶寬,應(yīng)該不會(huì)有明顯變化。

    posted @ 2014-07-15 10:09 順其自然EVO 閱讀(246) | 評(píng)論 (0)編輯 收藏

    移動(dòng)前端開發(fā)之?dāng)?shù)據(jù)庫操作篇

     在移動(dòng)平臺(tái)開發(fā)中,經(jīng)常會(huì)有大數(shù)據(jù)存儲(chǔ)與交互的操作,在以webkit為內(nèi)核的瀏覽器中,提供了一個(gè)叫作WEBSQL的數(shù)據(jù)庫。這讓我們前端也可以像php等程序語言一樣,進(jìn)行數(shù)據(jù)庫的讀寫操作。Web Storage存儲(chǔ)本地?cái)?shù)據(jù)的方法目前可以在許多主流瀏覽器、平臺(tái)與設(shè)備上實(shí)現(xiàn),與之相關(guān)的API也已經(jīng)標(biāo)準(zhǔn)化,但是,Web Storage存儲(chǔ)空間是有5MB,鍵值存儲(chǔ)的方式帶來諸多不便,未來本地存儲(chǔ)也不僅僅是這一種方法。其中最為熟知的就是Web SQL數(shù)據(jù)庫,它內(nèi)置SQLite數(shù)據(jù)庫,對(duì)數(shù)據(jù)庫的操作可以通過調(diào)用executeSql()方法實(shí)現(xiàn),允許使用JavaScript代碼控制數(shù)據(jù)庫。這樣一來,前端應(yīng)用就有了一個(gè)更為廣闊的天空。
      打開與創(chuàng)建數(shù)據(jù)庫
      如果要通過WebDb進(jìn)行本地?cái)?shù)據(jù)的存儲(chǔ),首先需要打開或創(chuàng)建一個(gè)數(shù)據(jù)庫,打開或創(chuàng)建數(shù)據(jù)庫的API是openDatabase,其調(diào)用的代碼如下所示:
      openDatabase(DbName,DBVersion,DBDescribe,DBSize,Callback());
      參數(shù)分別表示數(shù)據(jù)庫名稱,版本號(hào),描述,數(shù)據(jù)庫大小(字節(jié)為單位),創(chuàng)建或打開成功后執(zhí)行的回調(diào)函數(shù)。
      主要用到的有如下三個(gè)方法:
      1、openDatabase:這個(gè)方法使用現(xiàn)有數(shù)據(jù)庫或創(chuàng)建新數(shù)據(jù)庫創(chuàng)建數(shù)據(jù)庫對(duì)象。
      2、transaction:這個(gè)方法允許我們根據(jù)情況控制事務(wù)提交或回滾。
      3、executeSql:這個(gè)方法用于執(zhí)行真實(shí)的SQL查詢。
      下面我們就以具體的示例進(jìn)行演示。
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Database API</title>
    </head>
    <body>
    <script type="text/javascript">
    //數(shù)據(jù)文件在谷歌瀏覽器下,默認(rèn)存放的位置
    //"C:/Users/Administrator/AppData/Local/Google/Chrome/User Data/Default/databases/1";
    if(window.openDatabase){
    //如果test數(shù)據(jù)庫存在,則打開,否則會(huì)自動(dòng)創(chuàng)建
    var db  =  openDatabase("test", "1.0", "Database test", 1024 * 1024);
    //創(chuàng)建一個(gè)學(xué)生表
    var sql = 'CREATE TABLE  if not exists "student" ('+
    '"_id"  INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,'+
    '"name"  TEXT NOT NULL,'+
    '"age"  TEXT,'+
    '"mark"  TEXT)';
    //寫入一條數(shù)據(jù)
    var sql2 = 'insert into student (name,age,mark) values ("frog",1,"nice frog") ';
    //取出一行數(shù)據(jù)
    var sql3 = 'select * from student';
    //預(yù)處理語句的用法
    var sql4 = 'insert into student (name,age,mark) values (:name,:age,:mark)';
    /**
    * 預(yù)處理語句在php中也有類似的用法
    * $stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
    * $stmt->bindParam(':name', $name);
    * $stmt->bindParam(':value', $value);
    */
    var name = 'aron';
    var age  = 29;
    var mark = 'hello world';
    exec(sql,function(rs){
    //這里之所以要用回調(diào),
    //是因?yàn)閿?shù)據(jù)操作過程是異步的
    exec(sql2,function(rs){
    exec(sql3,function(rs){
    console.log(rs.rows.item(0))
    })
    exec2(sql4,[name,age,mark])
    })
    });
    //簡單封裝一個(gè)數(shù)據(jù)操作的方法
    function exec(sql,callback){
    db.transaction(function(tx){
    //中間這個(gè)[],在預(yù)處理語句中綁值
    tx.executeSql(sql,[],function(tx,rs){
    //success
    callback && callback(rs);
    },function(tx,msg){
    //error
    console.log(msg);
    });
    });
    }
    //支持變量邦定
    function exec2(sql,para,callback){
    para = para || [];
    db.transaction(function(tx){
    tx.executeSql(sql,para,function(tx,rs){
    //success
    callback && callback(rs);
    },function(tx,msg){
    //error
    console.log(msg);
    });
    });
    }
    }
    </script>
    </body>
    </html>
      以上代碼另存為html文件,在谷歌瀏覽器上,打開控制臺(tái),可以看到運(yùn)行的結(jié)果。
      局限性:
      可惜,我測試了下程序員最喜歡用的Firefox瀏覽器,可惜它并不支持這種本地?cái)?shù)據(jù)庫SQLite,且有可能被indexDB所替代的趨勢。

    posted @ 2014-07-10 19:40 順其自然EVO 閱讀(631) | 評(píng)論 (0)編輯 收藏

    Java系統(tǒng)開發(fā)框架

     做項(xiàng)目的時(shí)候,最需要快速開發(fā)框架來輔助。好的快速安全的開發(fā)框架,使得開發(fā)起來得心應(yīng)手。只需要關(guān)注業(yè)務(wù)的細(xì)節(jié),業(yè)務(wù)流程出來了,設(shè)計(jì)完成,就可以快速開發(fā)實(shí)現(xiàn)。 最近在做的一個(gè)項(xiàng)目就是如此,本身是一個(gè)開發(fā)平臺(tái),集成了e表報(bào)表工具,使得復(fù)雜的多變統(tǒng)計(jì)分析報(bào)表做起來事半功倍。 集成eworkflow工作流系統(tǒng),主要業(yè)務(wù)流程都可以先圖形化的設(shè)計(jì)好,表單可以用eform的電子表單也可以集成定制的頁面。多變的業(yè)務(wù)流都可以先定義好,圖形化的方式展現(xiàn)出來,業(yè)務(wù)流程實(shí)例也可用圖形的方式追蹤管理。
      java開發(fā)框架主要以后臺(tái)的MVC框架為主,有統(tǒng)一的入口portal, 環(huán)境類,數(shù)據(jù)庫連接方式。 頁面請(qǐng)求對(duì)應(yīng)的后臺(tái)handler類,輸入輸出元素的傳遞。 DB操作的封裝,復(fù)雜的sql查詢直接用統(tǒng)一封裝的jdbc操作工具實(shí)現(xiàn)。單表的增刪改查用一個(gè)單表操作的orm工具。單表的orm操作工具,有生成表類對(duì)象的工具,封裝的通用組合查詢字段的方法,單表保存方法,刪除方法,按主鍵查詢,給字段賦值的方法。 前臺(tái)頁面部分集成jquery框架,jsp頁面中集成標(biāo)簽庫,使得代碼和js分離,頁面更容易維護(hù)。
      系統(tǒng)開發(fā)框架圖
      ui部分,通過input和output對(duì)象達(dá)到頁面和后臺(tái)handler類的交互。
      BH類實(shí)現(xiàn)業(yè)務(wù)Handler抽象類,主要為各業(yè)務(wù)模塊提供實(shí)現(xiàn)方法。
      BL 部分實(shí)現(xiàn)業(yè)務(wù)規(guī)則和業(yè)務(wù)邏輯和調(diào)用db層的操作
      DB層有封裝的jdbc 的操作和單表的orm映射工具,復(fù)雜的操作可以用jdbc的封裝來完成。
      對(duì)象關(guān)系模型圖
      1、Portal:系統(tǒng)統(tǒng)一入口,在系統(tǒng)中扮演Controller角色,負(fù)責(zé)對(duì)handler類和jsp頁面定向的調(diào)度以及數(shù)據(jù)庫連接的分發(fā)。
      2、InputObject:輸入對(duì)象,負(fù)責(zé)收集頁面中提交的元素。
      3、OutputObject:輸出類,負(fù)責(zé)將經(jīng)處理的結(jié)果集、提示信息、異常信息傳輸?shù)角芭_(tái)頁面
      4、BusinessHandler:具體模塊的controller類,為每個(gè)業(yè)務(wù)提供具體的操作方法
      5、Peer類:db訪問類
    系統(tǒng)運(yùn)行時(shí)序圖
      上圖中訪問db返回resultSet不對(duì),訪問db返回的是List<Map<String,Object>>, 一條記錄就是List一個(gè)元素,字段名為map對(duì)象的key,字段值就會(huì)Object。
      先記錄這些了,有對(duì)這java開發(fā)框架感興趣的話,以后再續(xù)上更多的資料

    posted @ 2014-07-10 19:39 順其自然EVO 閱讀(258) | 評(píng)論 (0)編輯 收藏

    使用JUnit來測試Java代碼中的異常

      使用JUnit來測試Java代碼中的異常有很多種方式,你知道幾種?
      給定這樣一個(gè)class。
    Person.java
    public class Person {
    private String name;
    private int age;
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public int getAge() {
    return age;
    }
    public void setAge(int age) {
    if (age < 0 ) {
    throw new IllegalArgumentException("age is invalid");
    }
    this.age = age;
    }
    }
      我們來測試setAge方法。
    Try-catch 方式
    @Test
    public void shouldGetExceptionWhenAgeLessThan0() {
    Person person = new Person();
    try {
    person.setAge(-1);
    fail("should get IllegalArgumentException");
    } catch (IllegalArgumentException ex) {
    assertThat(ex.getMessage(),containsString("age is invalid"));
    }
    }
      這是最容易想到的一種方式,但是太啰嗦。
    JUnit annotation方式
      JUnit中提供了一個(gè)expected的annotation來檢查異常。
    @Test(expected = IllegalArgumentException.class)
    public void shouldGetExceptionWhenAgeLessThan0() {
    Person person = new Person();
    person.setAge(-1);
    }
      這種方式看起來要簡潔多了,但是無法檢查異常中的消息。
      ExpectedException rule
      JUnit7以后提供了一個(gè)叫做ExpectedException的Rule來實(shí)現(xiàn)對(duì)異常的測試。
    @Rule
    public ExpectedException exception = ExpectedException.none();
    @Test
    public void shouldGetExceptionWhenAgeLessThan0() {
    Person person = new Person();
    exception.expect(IllegalArgumentException.class);
    exception.expectMessage(containsString("age is invalid"));
    person.setAge(-1);
    }
      這種方式既可以檢查異常類型,也可以驗(yàn)證異常中的消息。
      使用catch-exception庫
      有個(gè)catch-exception庫也可以實(shí)現(xiàn)對(duì)異常的測試。
      首先引用該庫。
      pom.xml
      <dependency>
      <groupId>com.googlecode.catch-exception</groupId>
      <artifactId>catch-exception</artifactId>
      <version>1.2.0</version>
      <scope>test</scope> <!-- test scope to use it only in tests -->
      </dependency>
      然后這樣書寫測試。
      @Test
      public void shouldGetExceptionWhenAgeLessThan0() {
      Person person = new Person();
      catchException(person).setAge(-1);
      assertThat(caughtException(),instanceOf(IllegalArgumentException.class));
      assertThat(caughtException().getMessage(), containsString("age is invalid"));
      }
      這樣的好處是可以精準(zhǔn)的驗(yàn)證異常是被測方法拋出來的,而不是其它方法拋出來的。
      catch-exception庫還提供了多種API來進(jìn)行測試。
      先加載fest-assertion庫。
      <dependency>
      <groupId>org.easytesting</groupId>
      <artifactId>fest-assert-core</artifactId>
      <version>2.0M10</version>
      </dependency>

    然后可以書寫B(tài)DD風(fēng)格的測試。
    @Test
    public void shouldGetExceptionWhenAgeLessThan0() {
    // given
    Person person = new Person();
    // when
    when(person).setAge(-1);
    // then
    then(caughtException())
    .isInstanceOf(IllegalArgumentException.class)
    .hasMessage("age is invalid")
    .hasNoCause();
    }
      如果喜歡Hamcrest風(fēng)格的驗(yàn)證風(fēng)格的話,catch-exception也提供了相應(yīng)的Matcher API。
    @Test
    public void shouldGetExceptionWhenAgeLessThan0() {
    // given
    Person person = new Person();
    // when
    when(person).setAge(-1);
    // then
    assertThat(caughtException(), allOf(
    instanceOf(IllegalArgumentException.class)
    , hasMessage("age is invalid")
    ,hasNoCause()));
    }
      第一種最土鱉,第二種最簡潔,第四種最靠譜。

    posted @ 2014-07-10 19:26 順其自然EVO 閱讀(2542) | 評(píng)論 (0)編輯 收藏

    互聯(lián)網(wǎng)業(yè)務(wù)測試團(tuán)隊(duì)如果快速構(gòu)建輕量級(jí)的自動(dòng)化




     做測試,自動(dòng)化是一個(gè)繞不開的主題,而且也是非常值得去做的事情,無論是對(duì)測試質(zhì)量和效率的提升,還是對(duì)人的能力的鍛煉,都是非常的有幫助。就目前個(gè)人觀察到的情況,一些負(fù)責(zé)基礎(chǔ)性組件測試的團(tuán)隊(duì),比如底層平臺(tái)、SDK等,或者是負(fù)責(zé)功能通用性高的產(chǎn)品,比如防火墻、郵件系統(tǒng)等,都可以做到比較高的自動(dòng)化率,而且自動(dòng)化測試開發(fā)的過程通常也沒有那么糾結(jié)。相比而言,強(qiáng)應(yīng)用層業(yè)務(wù)相關(guān)的測試團(tuán)隊(duì),通常在自動(dòng)化方面的開展要困難很多。我這里說的是比較全面的功能的自動(dòng)化,不是指寫幾個(gè)簡單的腳步覆蓋幾個(gè)功能,大的思路是接口層面,不涉及UI的,而且可以制作大規(guī)模的用例。
      主要有幾個(gè)問題:
      1. 首要的問題是版本的節(jié)奏,互聯(lián)網(wǎng)的產(chǎn)品版本的節(jié)奏非常快,一個(gè)20多人的測試團(tuán)隊(duì)一周發(fā)布上百個(gè)功能特性是一件很普通的事情。團(tuán)隊(duì)成員有非常多的精力消耗在這些功能版本上,需要快速的理解業(yè)務(wù),構(gòu)建測試環(huán)境,bug驗(yàn)證回歸,以及發(fā)布上線等等,留給業(yè)務(wù)測試同學(xué)構(gòu)建自動(dòng)化用例的時(shí)間非常少。
      2. 功能非常的龐雜,而且有負(fù)責(zé)的業(yè)務(wù)流程,難以標(biāo)準(zhǔn)化。
      3. 說到自動(dòng)化,大家會(huì)想到自動(dòng)化框架,需要有一個(gè)比較好的自動(dòng)化框架。自己開發(fā)或者維護(hù)過框架的同學(xué)可能都深有體會(huì),這絕不是一件容易的事情,其工作量和持續(xù)的時(shí)間往往會(huì)超出我們的預(yù)期。我們是否有足夠的測試開發(fā)人力能做自己的框架,以及業(yè)務(wù)能否承受這樣的等待時(shí)間?
      互聯(lián)網(wǎng)行業(yè)的變化很快,線上功能變化按天算,業(yè)務(wù)調(diào)整和組織架構(gòu)調(diào)整按月看,做一個(gè)大的框架如果在部門層面還有可能,到了業(yè)務(wù)測試團(tuán)隊(duì)來說比較奢侈。很多方案是環(huán)境和需求逼出來的,細(xì)想下來,有兩條路,一是看部門的框架,二是有沒有輕量級(jí)的方案,可以快速的應(yīng)用。
      這里結(jié)合我們自己的一些實(shí)踐來看看,也是一點(diǎn)淺顯的經(jīng)驗(yàn)。
      部門有一些平臺(tái),但是有一些局限,主要是針對(duì)HTTP協(xié)議,另外對(duì)數(shù)據(jù)的準(zhǔn)備支持不太好,也不支持DB的數(shù)據(jù)檢查等功能,另外就是不太方面去定制和擴(kuò)展,相比而言更適合外網(wǎng)的監(jiān)控,評(píng)估下來準(zhǔn)備想想別的辦法。
      很多時(shí)候,過去的成功經(jīng)驗(yàn)往往會(huì)讓我們想復(fù)用,所以一開始的時(shí)候準(zhǔn)備參照在以前公司做過的keyword driven的框架,把功能點(diǎn)封裝成一個(gè)個(gè)的步驟,然后通過配置文件來構(gòu)造用例,實(shí)現(xiàn)自由的組合和數(shù)據(jù)驅(qū)動(dòng)。這條路驗(yàn)證過,而且看起來對(duì)現(xiàn)在的業(yè)務(wù)來說也沒有什么問題,能走通,但是就目前團(tuán)隊(duì)的情況來看,開發(fā)一個(gè)這樣的框架的代價(jià)無法承受。
      考慮了很久,于是有了現(xiàn)在更輕量點(diǎn)的做法,寫出來給那些測試開發(fā)資源比較少的業(yè)務(wù)測試為主的團(tuán)隊(duì)參考。
      如果想要快速,但是又功能豐富,最好的辦法就是抱一條粗腿,這里我們選的是JMeter。從2.2版本到最近的2.11,一直在關(guān)注和使用,發(fā)現(xiàn)JMeter的進(jìn)步很快,版本活躍程度也很高,另外,它早就超出了一個(gè)HTTP性能測試工具的范疇,自動(dòng)化測試其實(shí)是它另一個(gè)很大的主打,官方文檔也提到。
      選中JMeter簡單來說有幾點(diǎn):
      1. 接口大部分HTTP協(xié)議,而JMeter對(duì)HTTP支持非常全面,畢竟是做這個(gè)出身的。如果有些接口不是呢?我們的做法是用寫adapter轉(zhuǎn)換,這里不詳述,所以寫用例這邊還是按HTTP協(xié)議走。
      2. 對(duì)數(shù)據(jù)提取和斷言非常多的支持。還可以支持直連DB,可能需要補(bǔ)充額外的驅(qū)動(dòng)jar包,但是沒有技術(shù)障礙。
      3. 可以圖形界面,極大的方便了用例制作和調(diào)試。以前的經(jīng)驗(yàn),我們做了命令行的功能點(diǎn),后面為了大規(guī)模制作用例,還開發(fā)過web console,現(xiàn)在完全沒有必要,這一部分也省掉了。
      4. 可以命令行執(zhí)行,這就意味著可以方面的被粘合到我們的腳本里面。
      5. 輸入和輸出都是文本,jmx和存成的csv都是文本,極大的方便了腳本的處理和結(jié)果的parse。
      還有更多細(xì)節(jié)的點(diǎn)不多說了,有了這些基本可行性就很高了。想要獨(dú)自開發(fā)上面這些功能得很大的代價(jià),這也是輕量級(jí)能做到的主要原因。
      有了上面這些基本的骨架有了,但是要想想怎么整合成可復(fù)用和擴(kuò)展的用例。
      基本的思路如下:
      1. 用例的分層,為了更好的復(fù)用和管理。CGI是最小的粒度,對(duì)應(yīng)一個(gè)HTTP請(qǐng)求,完成一個(gè)很細(xì)節(jié)的操作。Function是一個(gè)對(duì)外有邏輯意義的歷史,比如下訂單,審核訂單。TestCase是一個(gè)成品,TestSuite是一個(gè)用例的集合。
      每個(gè)子系統(tǒng)的目錄組織如下:
      這里有個(gè)小的tricky的地方,為了部署的時(shí)候更靈活,希望腳本里面互相引用的文件是相對(duì)的路徑,但是JMeter支持不太好,默認(rèn)的根目錄是bin,所以簡單的做法是把整個(gè)自動(dòng)化用例的目錄copy到JMeter的bin下面。 2. 因?yàn)槲覀冇卸鄠€(gè)系統(tǒng),對(duì)應(yīng)多個(gè)測試小組,大家各有專注,而我們電商的業(yè)務(wù)又是一個(gè)長鏈條。function層就是我們復(fù)用的基礎(chǔ),里面再包含對(duì)CGI層接口的調(diào)用。這里有點(diǎn)JMeter的技術(shù)細(xì)節(jié),2.10開始建議用TestFragment來組織,而TestFragment是不能直接執(zhí)行的,只是些積木,到了TestCase層面再用ThreadGroup現(xiàn)場組,才可以執(zhí)行。
      下面是一個(gè)完整的TestCase,include了本系統(tǒng)和其他系統(tǒng)的一些function座位步驟。用例細(xì)節(jié)其實(shí)還有很多需要打磨的地方,比如命名規(guī)范,執(zhí)行起來不容易。
      3. 自動(dòng)化的報(bào)告,每次執(zhí)行完了之后自動(dòng)的發(fā)郵件報(bào)告出來。
     為了更好的定位問題,需要把每個(gè)接口執(zhí)行的細(xì)節(jié)也暴露出來,點(diǎn)擊詳情可以看到調(diào)用的情況,包括request和response的數(shù)據(jù)。
      除了好處,也有一些不方便的地方:
      1. JMeter在include其他的jmx腳本后,不能直接在界面顯示加載的內(nèi)容,所以看不到被include的腳本里面的步驟,調(diào)試的時(shí)候不方便。不過好在JMeter可以一套binary啟多個(gè),并著看。
      2. 最后的結(jié)果報(bào)告里面,不能控制展示的粒度,是直接攤開成CGI層面的步驟,顯得比較雜。
      目前我們執(zhí)行的情況
      1. 目前覆蓋了200多個(gè)CGI接口,以及100多個(gè)功能點(diǎn),初步有4個(gè)系統(tǒng)掛接到了自動(dòng)部署后的執(zhí)行。用例還在進(jìn)一步的擴(kuò)展中,框架不需要改動(dòng)。JMeter本身的穩(wěn)定性還是不錯(cuò)的。
      2. 整個(gè)過程,不算制作用例的時(shí)間,我們實(shí)際投入的測試開發(fā)的人力合起來不到一個(gè)人月。
      3. 大部分業(yè)務(wù)測試同學(xué)都參與到了用例的制作,提升了對(duì)業(yè)務(wù)邏輯的理解,并且對(duì)部分同學(xué)來說,也補(bǔ)了HTTP協(xié)議等基礎(chǔ)知識(shí)的課,實(shí)際動(dòng)手比聽聽培訓(xùn)效果要好。
      從實(shí)際的效果和投入來說還是比較滿意的。
      除了技術(shù)層面,自動(dòng)化執(zhí)行起來有幾個(gè)核心的要點(diǎn):
      1. 一定要強(qiáng)掛鉤到測試和發(fā)布的環(huán)節(jié)。
      這一點(diǎn)看起來沒那么重要,但是如果不希望自動(dòng)化成為花瓶,就必須要這樣做。像互聯(lián)網(wǎng)產(chǎn)品這樣快的節(jié)奏跑起來,任何花哨的環(huán)節(jié)會(huì)逐漸被洗掉,因?yàn)槿藛T的配比和版本的數(shù)量,不是必做的東西慢慢就堅(jiān)持不下來。所以自動(dòng)化如果要能發(fā)揮效果,目前來看最合適的點(diǎn)是在每次自動(dòng)部署后快速的刷一遍,在手工測試開始之前。而且如果要人工去點(diǎn),這事兒時(shí)間長了也不靠譜,一定要把這個(gè)過程也自動(dòng)化,版本在測試環(huán)境部署好了之后,自動(dòng)化自動(dòng)跑完,這就是強(qiáng)的掛鉤。
      2. 報(bào)告也是要自動(dòng)的,并且郵件抄送給相關(guān)的開發(fā),測試和團(tuán)隊(duì)的負(fù)責(zé)人。我們現(xiàn)在的做法是跑完了腳本解析后自動(dòng)的發(fā)郵件報(bào)告。
      3. 非100%成功的都要跟進(jìn)。
      寧愿少而精,這個(gè)也類似broken window理論,如果能容忍一個(gè)用例失敗,就會(huì)有2個(gè),3個(gè),也會(huì)讓自動(dòng)化慢慢失去意義。目前的做法是只要有失敗,對(duì)應(yīng)系統(tǒng)的負(fù)責(zé)同學(xué)要郵件reply all跟進(jìn)原因。
      4. 關(guān)注用例的細(xì)節(jié)
      團(tuán)隊(duì)的負(fù)責(zé)人要去看用例的質(zhì)量,而不只是用例的數(shù)量和執(zhí)行情況,比如斷言做到什么程度,哪些是寫死的哪些參數(shù)化了,功能之間的復(fù)用情況。其實(shí)這個(gè)和所有的事情一樣,如果真的重要,就應(yīng)該要跳進(jìn)去關(guān)注細(xì)節(jié)。
      其實(shí)說起來上面沒有什么高深的地方,道理也淺顯,可能是工作久了會(huì)變得更加務(wù)實(shí),最怕做了沒有用的東西。
      1. 關(guān)于技術(shù)含量的問題,不糾結(jié)。當(dāng)然,有能力和精力做到技術(shù)含量很好。但是沒有技術(shù)含量但是有價(jià)值 > 有技術(shù)含量效果不好。
      2. 盡可能的復(fù)用好的組件,核心的引擎不一定要自己做,特別是業(yè)務(wù)測試團(tuán)隊(duì)。用開源組件,自己開發(fā)特點(diǎn)需求,并把它們粘合起來。
      以上粗略的整理,希望給那些想要做功能自動(dòng)化,但是又受限于非常快得功能版本節(jié)奏,也沒有大量測試開發(fā)人力的業(yè)務(wù)測試團(tuán)隊(duì)一點(diǎn)參考。





    31/3123>






    posted @ 2014-07-10 19:23 順其自然EVO 閱讀(322) | 評(píng)論 (0)編輯 收藏

    如何做好安卓手機(jī)的performance測試?

    提問:如何做好安卓手機(jī)的performance測試?
      回答:任何測試在測試之前都應(yīng)該建立相應(yīng)的計(jì)劃或方案,手機(jī)的performance測試同樣也不例外,如何做好performance測試我認(rèn)為就是制定1個(gè)適應(yīng)公司需求的性能測試計(jì)劃,而好的測試計(jì)劃就需要包含下面幾個(gè)方面:
      1.Performance范圍的確立,手機(jī)常用的模塊性能必然需要納入測試范圍,如打開聯(lián)系人界面的時(shí)間、點(diǎn)擊撥號(hào)按鈕到顯示撥號(hào)UI的時(shí)間,這些都是重要的performance測試范圍,這些模塊的性能會(huì)影響到最終用戶的使用體驗(yàn);其次手機(jī)一些附件的性能需要考慮是否加入性能測試,如WIFI的吞吐率和距離、藍(lán)牙的吞吐率和距離、數(shù)據(jù)網(wǎng)絡(luò)的傳輸速率等等,這些在定制測試時(shí)一般是會(huì)有要求的,但由于附件性能是偏硬件的,需根據(jù)公司的實(shí)際情況,確定是否將其納入測試范圍
      2.Performance目標(biāo)的確立,我們不可能把被測手機(jī)最終的性能結(jié)果作為我們的驗(yàn)收結(jié)果,這樣就失去了性能測試的意義。確定performance的目標(biāo)是測試重要的1個(gè)環(huán)節(jié),如果用戶提供驗(yàn)收標(biāo)準(zhǔn),當(dāng)然是求之不得的,但實(shí)際中性能的標(biāo)準(zhǔn)往往是參考某一配置相近的上市機(jī)器來確定標(biāo)準(zhǔn)的,這種參考并不等于照搬,由于存在誤差,我的經(jīng)驗(yàn)是在參考機(jī)的基礎(chǔ)上乘以1.5的系數(shù)。
      3.Performance測試方法的確立,安卓手機(jī)模塊的性能測試有很多方法,最簡單的可以用秒表計(jì)時(shí),當(dāng)然這樣的誤差會(huì)較大。如果需要精確一點(diǎn)的可以通過log確定,從打開1個(gè)activity的開始時(shí)間到結(jié)束時(shí)間,adb的log都是可以看到的,但這個(gè)時(shí)間和用戶實(shí)際操作的時(shí)間仍然是有誤差的,這個(gè)只是程序邏輯上的時(shí)間,不等于用戶操作時(shí)的時(shí)間。最貼近用戶體驗(yàn)的方法是用精度高的攝像機(jī)拍攝視頻,然后通過軟件拆分視頻幀來計(jì)算時(shí)間,這樣的結(jié)果是最可靠的。無論才用什么方法,都需要采用多次測試求平均值的方法來減少誤差。關(guān)于附件性能的測試,一般都是使用相應(yīng)的工具進(jìn)行測試。
      4.Performance測試實(shí)施,測試范圍、測試目標(biāo)、測試方法確定完畢后,就需要明確性能測試什么時(shí)候進(jìn)行,什么時(shí)候結(jié)束,什么階段實(shí)現(xiàn)什么目標(biāo),最主要的是這些都必須時(shí)可衡量的。一般性能測試都是在alpha版本的milestone通過之后開始進(jìn)行,各個(gè)階段都需要執(zhí)行1個(gè)輪次或多個(gè)輪次的性能測試

    posted @ 2014-07-10 19:21 順其自然EVO 閱讀(336) | 評(píng)論 (0)編輯 收藏

    使用EasyMock更輕松地進(jìn)行測試

    測試驅(qū)動(dòng)開發(fā)是軟件開發(fā)的重要部分。如果代碼不進(jìn)行測試,就是不可靠的。所有代碼都必須測試,而且理想情況下應(yīng)該在編寫代碼之前編寫測試。但是,有些東西容易測試,有些東西不容易。如果要編寫一個(gè)代表貨幣值的簡單的類,那么很容易測試把 $1.23 和 $2.8 相加是否能夠得出 $4.03,而不是 $3.03 或 $4.029999998。測試是否不會(huì)出現(xiàn) $7.465 這樣的貨幣值也不太困難。但是,如何測試把 $7.50 轉(zhuǎn)換為 €5.88 的方法呢(尤其是在通過連接數(shù)據(jù)庫查詢隨時(shí)變動(dòng)的匯率信息的情況下)?在每次運(yùn)行程序時(shí),amount.toEuros() 的正確結(jié)果都可能有變化。
      答案是 mock 對(duì)象。測試并不通過連接真正的服務(wù)器來獲取最新的匯率信息,而是連接一個(gè) mock 服務(wù)器,它總是返回相同的匯率。這樣就可以得到可預(yù)測的結(jié)果,可以根據(jù)它進(jìn)行測試。畢竟,測試的目標(biāo)是 toEuros() 方法中的邏輯,而不是服務(wù)器是否發(fā)送正確的值。(那是構(gòu)建服務(wù)器的開發(fā)人員要操心的事)。這種 mock 對(duì)象有時(shí)候稱為 fake。
      mock 對(duì)象還有助于測試錯(cuò)誤條件。例如,如果 toEuros() 方法試圖獲取最新的匯率,但是網(wǎng)絡(luò)中斷了,那么會(huì)發(fā)生什么?可以把以太網(wǎng)線從計(jì)算機(jī)上拔出來,然后運(yùn)行測試,但是編寫一個(gè)模擬網(wǎng)絡(luò)故障的 mock 對(duì)象省事得多。
      mock 對(duì)象還可以測試類的行為。通過把斷言放在 mock 代碼中,可以檢查要測試的代碼是否在適當(dāng)?shù)臅r(shí)候把適當(dāng)?shù)膮?shù)傳遞給它的協(xié)作者。可以通過 mock 查看和測試類的私有部分,而不需要通過不必要的公共方法公開它們。
      最后,mock 對(duì)象有助于從測試中消除依賴項(xiàng)。它們使測試更單元化。涉及 mock 對(duì)象的測試中的失敗很可能是要測試的方法中的失敗,不太可能是依賴項(xiàng)中的問題。這有助于隔離問題和簡化調(diào)試。
      EasyMock 是一個(gè)針對(duì) Java 編程語言的開放源碼 mock 對(duì)象庫,可以幫助您快速輕松地創(chuàng)建用于這些用途的 mock 對(duì)象。EasyMock 使用動(dòng)態(tài)代理,讓您只用一行代碼就能夠創(chuàng)建任何接口的基本實(shí)現(xiàn)。通過添加 EasyMock 類擴(kuò)展,還可以為類創(chuàng)建 mock。可以針對(duì)任何用途配置這些 mock,從方法簽名中的簡單啞參數(shù)到檢驗(yàn)一系列方法調(diào)用的多調(diào)用測試。
      EasyMock 簡介
      現(xiàn)在通過一個(gè)具體示例演示 EasyMock 的工作方式。清單 1 是虛構(gòu)的 ExchangeRate 接口。與任何接口一樣,接口只說明實(shí)例要做什么,而不指定應(yīng)該怎么做。例如,它并沒有指定從 Yahoo 金融服務(wù)、政府還是其他地方獲取匯率數(shù)據(jù)。
      清單 1. ExchangeRate
      import java.io.IOException;
      public interface ExchangeRate {
      double getRate(String inputCurrency, String outputCurrency) throws IOException;
      }
      清單 2 是假定的 Currency 類的骨架。它實(shí)際上相當(dāng)復(fù)雜,很可能包含 bug。(您不必猜了:確實(shí)有 bug,實(shí)際上有不少)。
      清單 2. Currency 類
    import java.io.IOException;
    public class Currency {
    private String units;
    private long amount;
    private int cents;
    public Currency(double amount, String code) {
    this.units = code;
    setAmount(amount);
    }
    private void setAmount(double amount) {
    this.amount = new Double(amount).longValue();
    this.cents = (int) ((amount * 100.0) % 100);
    }
    public Currency toEuros(ExchangeRate converter) {
    if ("EUR".equals(units)) return this;
    else {
    double input = amount + cents/100.0;
    double rate;
    try {
    rate = converter.getRate(units, "EUR");
    double output = input * rate;
    return new Currency(output, "EUR");
    } catch (IOException ex) {
    return null;
    }
    }
    }
    public boolean equals(Object o) {
    if (o instanceof Currency) {
    Currency other = (Currency) o;
    return this.units.equals(other.units)
    && this.amount == other.amount
    && this.cents == other.cents;
    }
    return false;
    }
    public String toString() {
    return amount + "." + Math.abs(cents) + " " + units;
    }
    }
     Currency 類設(shè)計(jì)的一些重點(diǎn)可能不容易一下子看出來。匯率是從這個(gè)類之外 傳遞進(jìn)來的,并不是在類內(nèi)部構(gòu)造的。因此,很有必要為匯率創(chuàng)建 mock,這樣在運(yùn)行測試時(shí)就不需要與真正的匯率服務(wù)器通信。這還使客戶機(jī)應(yīng)用程序能夠使用不同的匯率數(shù)據(jù)源。
      清單 3 給出一個(gè) JUnit 測試,它檢查在匯率為 1.5 的情況下 $2.50 是否會(huì)轉(zhuǎn)換為 €3.75。使用 EasyMock 創(chuàng)建一個(gè)總是提供值 1.5 的ExchangeRate 對(duì)象。
      清單 3. CurrencyTest 類
    import junit.framework.TestCase;
    import org.easymock.EasyMock;
    import java.io.IOException;
    public class CurrencyTest extends TestCase {
    public void testToEuros() throws IOException {
    Currency expected = new Currency(3.75, "EUR");
    ExchangeRate mock = EasyMock.createMock(ExchangeRate.class);
    EasyMock.expect(mock.getRate("USD", "EUR")).andReturn(1.5);
    EasyMock.replay(mock);
    Currency actual = testObject.toEuros(mock);
    assertEquals(expected, actual);
    }
    }
      老實(shí)說,在我第一次運(yùn)行 清單 3 時(shí)失敗了,測試中經(jīng)常出現(xiàn)這種問題。但是,我已經(jīng)糾正了 bug。這就是我們采用 TDD 的原因。
      運(yùn)行這個(gè)測試,它通過了。發(fā)生了什么?我們來逐行看看這個(gè)測試。首先,構(gòu)造測試對(duì)象和預(yù)期的結(jié)果:
      Currency testObject = new Currency(2.50, "USD");
      Currency expected = new Currency(3.75, "EUR");
      這不是新東西。
      接下來,通過把 ExchangeRate 接口的 Class 對(duì)象傳遞給靜態(tài)的 EasyMock.createMock() 方法,創(chuàng)建這個(gè)接口的 mock 版本:
      ExchangeRate mock = EasyMock.createMock(ExchangeRate.class);
      這是到目前為止最不可思議的部分。注意,我可沒有編寫實(shí)現(xiàn) ExchangeRate 接口的類。另外,EasyMock.createMock() 方法絕對(duì)無法返回ExchangeRate 的實(shí)例,它根本不知道這個(gè)類型,這個(gè)類型是我為本文創(chuàng)建的。即使它能夠通過某種奇跡返回 ExchangeRate,但是如果需要模擬另一個(gè)接口的實(shí)例,又會(huì)怎么樣呢?
      我最初看到這個(gè)時(shí)也非常困惑。我不相信這段代碼能夠編譯,但是它確實(shí)可以。這里的 “黑魔法” 來自 Java 1.3 中引入的 Java 5 泛型和動(dòng)態(tài)代理(見 參考資料)。幸運(yùn)的是,您不需要了解它的工作方式(發(fā)明這些訣竅的程序員確實(shí)非常聰明)。
      下一步同樣令人吃驚。為了告訴 mock 期望什么結(jié)果,把方法作為參數(shù)傳遞給 EasyMock.expect() 方法。然后調(diào)用 andReturn() 指定調(diào)用這個(gè)方法應(yīng)該得到什么結(jié)果:
      EasyMock.expect(mock.getRate("USD", "EUR")).andReturn(1.5);
      EasyMock 記錄這個(gè)調(diào)用,因此知道以后應(yīng)該重放什么。
      如果在使用 mock 之前忘了調(diào)用 EasyMock.replay(),那么會(huì)出現(xiàn) IllegalStateException 異常和一個(gè)沒有什么幫助的錯(cuò)誤消息:missing behavior definition for the preceding method call。
      接下來,通過調(diào)用 EasyMock.replay() 方法,讓 mock 準(zhǔn)備重放記錄的數(shù)據(jù):
      EasyMock.replay(mock);
      這是讓我比較困惑的設(shè)計(jì)之一。EasyMock.replay() 不會(huì)實(shí)際重放 mock。而是重新設(shè)置 mock,在下一次調(diào)用它的方法時(shí),它將開始重放。
      現(xiàn)在 mock 準(zhǔn)備好了,我把它作為參數(shù)傳遞給要測試的方法:
      為類創(chuàng)建 mock
      從實(shí)現(xiàn)的角度來看,很難為類創(chuàng)建 mock。不能為類創(chuàng)建動(dòng)態(tài)代理。標(biāo)準(zhǔn)的 EasyMock 框架不支持類的 mock。但是,EasyMock 類擴(kuò)展使用字節(jié)碼操作產(chǎn)生相同的效果。您的代碼中采用的模式幾乎完全一樣。只需導(dǎo)入org.easymock.classextension.EasyMock 而不是org.easymock.EasyMock。為類創(chuàng)建 mock 允許把類中的一部分方法替換為 mock,而其他方法保持不變。
      Currency actual = testObject.toEuros(mock);
      最后,檢查結(jié)果是否符合預(yù)期:
      assertEquals(expected, actual);
      這就完成了。如果有一個(gè)需要返回特定值的接口需要測試,就可以快速地創(chuàng)建一個(gè) mock。這確實(shí)很容易。ExchangeRate 接口很小很簡單,很容易為它手工編寫 mock 類。但是,接口越大越復(fù)雜,就越難為每個(gè)單元測試編寫單獨(dú)的 mock。通過使用 EasyMock,只需一行代碼就能夠創(chuàng)建 java.sql.ResultSet 或 org.xml.sax.ContentHandler 這樣的大型接口的實(shí)現(xiàn),然后向它們提供運(yùn)行測試所需的行為。
      測試異常
      mock 最常見的用途之一是測試異常條件。例如,無法簡便地根據(jù)需要制造網(wǎng)絡(luò)故障,但是可以創(chuàng)建模擬網(wǎng)絡(luò)故障的 mock。
      當(dāng) getRate() 拋出 IOException 時(shí),Currency 類應(yīng)該返回 null。清單 4 測試這一點(diǎn):
      清單 4. 測試方法是否拋出正確的異常
    public void testExchangeRateServerUnavailable() throws IOException {
    ExchangeRate mock = EasyMock.createMock(ExchangeRate.class);
    EasyMock.expect(mock.getRate("USD", "EUR")).andThrow(new IOException());
    EasyMock.replay(mock);
    Currency actual = testObject.toEuros(mock);
    assertNull(actual);
    }
      這里的新東西是 andThrow() 方法。顧名思義,它只是讓 getRate() 方法在被調(diào)用時(shí)拋出指定的異常。
      可以拋出您需要的任何類型的異常(已檢查、運(yùn)行時(shí)或錯(cuò)誤),只要方法簽名支持它即可。這對(duì)于測試極其少見的條件(例如內(nèi)存耗盡錯(cuò)誤或無法找到類定義)或表示虛擬機(jī) bug 的條件(比如 UTF-8 字符編碼不可用)尤其有幫助。
      設(shè)置預(yù)期
      EasyMock 不只是能夠用固定的結(jié)果響應(yīng)固定的輸入。它還可以檢查輸入是否符合預(yù)期。例如,假設(shè) toEuros() 方法有一個(gè) bug(見清單 5),它返回以歐元為單位的結(jié)果,但是獲取的是加拿大元的匯率。這會(huì)讓客戶發(fā)一筆意外之財(cái)或遭受重大損失。
      清單 5. 有 bug 的 toEuros() 方法
    public Currency toEuros(ExchangeRate converter) {
    if ("EUR".equals(units)) return this;
    else {
    double input = amount + cents/100.0;
    double rate;
    try {
    rate = converter.getRate(units, "CAD");
    double output = input * rate;
    return new Currency(output, "EUR");
    } catch (IOException e) {
    return null;
    }
    }
    }
      但是,不需要為此編寫另一個(gè)測試。清單 4 中的 testToEuros 能夠捕捉到這個(gè) bug。當(dāng)對(duì)這段代碼運(yùn)行清單 4 中的測試時(shí),測試會(huì)失敗并顯示以下錯(cuò)誤消息:
      "java.lang.AssertionError:
      Unexpected method call getRate("USD", "CAD"):
      getRate("USD", "EUR"): expected: 1, actual: 0".
      注意,這并不是我設(shè)置的斷言。EasyMock 注意到我傳遞的參數(shù)不符合測試用例。
      在默認(rèn)情況下,EasyMock 只允許測試用例用指定的參數(shù)調(diào)用指定的方法。但是,有時(shí)候這有點(diǎn)兒太嚴(yán)格了,所以有辦法放寬這一限制。例如,假設(shè)希望允許把任何字符串傳遞給 getRate() 方法,而不僅限于 USD 和 EUR。那么,可以指定 EasyMock.anyObject() 而不是顯式的字符串,如下所示:
      EasyMock.expect(mock.getRate(
      (String) EasyMock.anyObject(),
      (String) EasyMock.anyObject())).andReturn(1.5);
      還可以更挑剔一點(diǎn)兒,通過指定 EasyMock.notNull() 只允許非 null 字符串:
      EasyMock.expect(mock.getRate(
      (String) EasyMock.notNull(),
      (String) EasyMock.notNull())).andReturn(1.5);
      靜態(tài)類型檢查會(huì)防止把非 String 對(duì)象傳遞給這個(gè)方法。但是,現(xiàn)在允許傳遞 USD 和 EUR 之外的其他 String。還可以通過EasyMock.matches() 使用更顯式的正則表達(dá)式。下面指定需要一個(gè)三字母的大寫 ASCII String:
      EasyMock.expect(mock.getRate(
      (String) EasyMock.matches("[A-Z][A-Z][A-Z]"),
      (String) EasyMock.matches("[A-Z][A-Z][A-Z]"))).andReturn(1.5);
      使用 EasyMock.find() 而不是 EasyMock.matches(),就可以接受任何包含三字母大寫子 String 的 String。 EasyMock 為基本數(shù)據(jù)類型提供相似的方法:
      EasyMock.anyInt()
      EasyMock.anyShort()
      EasyMock.anyByte()
      EasyMock.anyLong()
      EasyMock.anyFloat()
      EasyMock.anyDouble()
      EasyMock.anyBoolean()
      對(duì)于數(shù)字類型,還可以使用 EasyMock.lt(x) 接受小于 x 的任何值,或使用 EasyMock.gt(x) 接受大于 x 的任何值。
      在檢查一系列預(yù)期時(shí),可以捕捉一個(gè)方法調(diào)用的結(jié)果或參數(shù),然后與傳遞給另一個(gè)方法調(diào)用的值進(jìn)行比較。最后,通過定義定制的匹配器,可以檢查參數(shù)的任何細(xì)節(jié),但是這個(gè)過程比較復(fù)雜。但是,對(duì)于大多數(shù)測試,EasyMock.anyInt()、EasyMock.matches() 和 EasyMock.eq() 這樣的基本匹配器已經(jīng)足夠了。
      嚴(yán)格的 mock 和次序檢查
      EasyMock 不僅能夠檢查是否用正確的參數(shù)調(diào)用預(yù)期的方法。它還可以檢查是否以正確的次序調(diào)用這些方法,而且只調(diào)用了這些方法。在默認(rèn)情況下,不執(zhí)行這種檢查。要想啟用它,應(yīng)該在測試方法末尾調(diào)用 EasyMock.verify(mock)。例如,如果 toEuros() 方法不只一次調(diào)用getRate(),清單 6 就會(huì)失敗。
      清單 6. 檢查是否只調(diào)用 getRate() 一次
    public void testToEuros() throws IOException {
    Currency expected = new Currency(3.75, "EUR");
    ExchangeRate mock = EasyMock.createMock(ExchangeRate.class);
    EasyMock.expect(mock.getRate("USD", "EUR")).andReturn(1.5);
    EasyMock.replay(mock);
    Currency actual = testObject.toEuros(mock);
    assertEquals(expected, actual);
    EasyMock.verify(mock);
    }
      EasyMock.verify() 究竟做哪些檢查取決于它采用的操作模式:
      Normal — EasyMock.createMock():必須用指定的參數(shù)調(diào)用所有預(yù)期的方法。但是,不考慮調(diào)用這些方法的次序。調(diào)用未預(yù)期的方法會(huì)導(dǎo)致測試失敗。
      Strict — EasyMock.createStrictMock():必須以指定的次序用預(yù)期的參數(shù)調(diào)用所有預(yù)期的方法。調(diào)用未預(yù)期的方法會(huì)導(dǎo)致測試失敗。
      Nice — EasyMock.createNiceMock():必須以任意次序用指定的參數(shù)調(diào)用所有預(yù)期的方法。調(diào)用未預(yù)期的方法不會(huì) 導(dǎo)致測試失敗。Nice mock 為沒有顯式地提供 mock 的方法提供合理的默認(rèn)值。返回?cái)?shù)字的方法返回 0,返回布爾值的方法返回 false。返回對(duì)象的方法返回 null。
      檢查調(diào)用方法的次序和次數(shù)對(duì)于大型接口和大型測試更有意義。例如,請(qǐng)考慮 org.xml.sax.ContentHandler 接口。如果要測試一個(gè) XML 解析器,希望輸入文檔并檢查解析器是否以正確的次序調(diào)用 ContentHandler 中正確的方法。例如,請(qǐng)考慮清單 7 中的簡單 XML 文檔:
      清單 7. 簡單的 XML 文檔
      <root>
      Hello World!
      </root>
      根據(jù) SAX 規(guī)范,在解析器解析文檔時(shí),它應(yīng)該按以下次序調(diào)用這些方法:
      setDocumentLocator()
      startDocument()
      startElement()
      characters()
      endElement()
      endDocument()
      但是,更有意思的是,對(duì) setDocumentLocator() 的調(diào)用是可選的;解析器可以多次調(diào)用 characters()。它們不需要在一次調(diào)用中傳遞盡可能多的連續(xù)文本,實(shí)際上大多數(shù)解析器不這么做。即使是對(duì)于清單 7 這樣的簡單文檔,也很難用傳統(tǒng)的方法測試 XML 解析器,但是 EasyMock 大大簡化了這個(gè)任務(wù),見清單 8:
      清單 8. 測試 XML 解析器
    import java.io.*;
    import org.easymock.EasyMock;
    import org.xml.sax.*;
    import org.xml.sax.helpers.XMLReaderFactory;
    import junit.framework.TestCase;
    public class XMLParserTest extends TestCase {
    private  XMLReader parser;
    protected void setUp() throws Exception {
    parser = XMLReaderFactory.createXMLReader();
    }
    public void testSimpleDoc() throws IOException, SAXException {
    String doc = "<root>\n  Hello World!\n</root>";
    ContentHandler mock = EasyMock.createStrictMock(ContentHandler.class);
    mock.setDocumentLocator((Locator) EasyMock.anyObject());
    EasyMock.expectLastCall().times(0, 1);
    mock.startDocument();
    mock.startElement(EasyMock.eq(""), EasyMock.eq("root"), EasyMock.eq("root"),
    (Attributes) EasyMock.anyObject());
    mock.characters((char[]) EasyMock.anyObject(),
    EasyMock.anyInt(), EasyMock.anyInt());
    EasyMock.expectLastCall().atLeastOnce();
    mock.endElement(EasyMock.eq(""), EasyMock.eq("root"), EasyMock.eq("root"));
    mock.endDocument();
    EasyMock.replay(mock);
    parser.setContentHandler(mock);
    InputStream in = new ByteArrayInputStream(doc.getBytes("UTF-8"));
    parser.parse(new InputSource(in));
    EasyMock.verify(mock);
    }
    }
      這個(gè)測試展示了幾種新技巧。首先,它使用一個(gè) strict mock,因此要求符合指定的次序。例如,不希望解析器在調(diào)用 startDocument() 之前調(diào)用 endDocument()。
      第二,要測試的所有方法都返回 void。這意味著不能把它們作為參數(shù)傳遞給 EasyMock.expect()(就像對(duì) getRate() 所做的)。(EasyMock 在許多方面能夠 “欺騙” 編譯器,但是還不足以讓編譯器相信 void 是有效的參數(shù)類型)。因此,要在 mock 上調(diào)用 void 方法,由 EasyMock 捕捉結(jié)果。如果需要修改預(yù)期的細(xì)節(jié),那么在調(diào)用 mock 方法之后立即調(diào)用 EasyMock.expectLastCall()。另外注意,不能作為預(yù)期參數(shù)傳遞任何 String、int 和數(shù)組。必須先用 EasyMock.eq() 包裝它們,這樣才能在預(yù)期中捕捉它們的值。
      清單 8 使用 EasyMock.expectLastCall() 調(diào)整預(yù)期的方法調(diào)用次數(shù)。在默認(rèn)情況下,預(yù)期的方法調(diào)用次數(shù)是一次。但是,我通過調(diào)用.times(0, 1) 把 setDocumentLocator() 設(shè)置為可選的。這指定調(diào)用此方法的次數(shù)必須是零次或一次。當(dāng)然,可以根據(jù)需要把預(yù)期的方法調(diào)用次數(shù)設(shè)置為任何范圍,比如 1-10 次、3-30 次。對(duì)于 characters(),我實(shí)際上不知道將調(diào)用它多少次,但是知道必須至少調(diào)用一次,所以對(duì)它使用 .atLeastOnce()。如果這是非 void 方法,就可以對(duì)預(yù)期直接應(yīng)用 times(0, 1) 和 atLeastOnce()。但是,因?yàn)檫@些方法返回 void,所以必須通過 EasyMock.expectLastCall() 設(shè)置它們。
      最后注意,這里對(duì) characters() 的參數(shù)使用了 EasyMock.anyObject() 和 EasyMock.anyInt()。這考慮到了解析器向 ContentHandler 傳遞文本的各種方式。
      mock 和真實(shí)性
      有必要使用 EasyMock 嗎?其實(shí),手工編寫的 mock 類也能夠?qū)崿F(xiàn) EasyMock 的功能,但是手工編寫的類只能適用于某些項(xiàng)目。例如,對(duì)于 清單 3,手工編寫一個(gè)使用匿名內(nèi)部類的 mock 也很容易,代碼很緊湊,對(duì)于不熟悉 EasyMock 的開發(fā)人員可讀性可能更好。但是,它是一個(gè)專門為本文構(gòu)造的簡單示例。在為 org.w3c.dom.Node(25 個(gè)方法)或 java.sql.ResultSet(139 個(gè)方法而且還在增加)這樣的大型接口創(chuàng)建 mock 時(shí),EasyMock 能夠大大節(jié)省時(shí)間,以最低的成本創(chuàng)建更短更可讀的代碼。
      最后,提出一條警告:使用 mock 對(duì)象可能做得太過分。可能把太多的東西替換為 mock,導(dǎo)致即使在代碼質(zhì)量很差的情況下,測試仍然總是能夠通過。替換為 mock 的東西越多,接受測試的東西就越少。依賴庫以及方法與其調(diào)用的方法之間的交互中可能存在許多 bug。把依賴項(xiàng)替換為 mock 會(huì)隱藏許多實(shí)際上可能發(fā)現(xiàn)的 bug。在任何情況下,mock 都不應(yīng)該是您的第一選擇。如果能夠使用真實(shí)的依賴項(xiàng),就應(yīng)該這么做。mock 是真實(shí)類的粗糙的替代品。但是,如果由于某種原因無法用真實(shí)的類可靠且自動(dòng)地進(jìn)行測試,那么用 mock 進(jìn)行測試肯定比根本不測試強(qiáng)。

    posted @ 2014-07-10 19:20 順其自然EVO 閱讀(3424) | 評(píng)論 (0)編輯 收藏

    僅列出標(biāo)題
    共394頁: First 上一頁 85 86 87 88 89 90 91 92 93 下一頁 Last 
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導(dǎo)航

    統(tǒng)計(jì)

    • 隨筆 - 3936
    • 文章 - 404
    • 評(píng)論 - 179
    • 引用 - 0

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    •  

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 91香焦国产线观看看免费| 成人免费视频软件网站| 在线a亚洲v天堂网2018| 无码少妇一区二区浪潮免费| 久久国产成人精品国产成人亚洲| 亚洲乱码卡三乱码新区| 91免费在线视频| 国产成人免费福利网站| 亚洲成a人片在线观看播放| 皇色在线免费视频| 日本免费一本天堂在线| 91嫩草亚洲精品| 老司机69精品成免费视频| 内射无码专区久久亚洲| 亚洲va在线va天堂成人| 久久免费观看国产99精品| 亚洲片一区二区三区| 亚洲国产成人久久综合| 日日麻批免费40分钟日本的| 亚洲精品国产精品乱码在线观看| 国产精品亚洲色图| 成年女人毛片免费播放人| 亚洲综合亚洲国产尤物| 99久久成人国产精品免费| www亚洲精品少妇裸乳一区二区| 亚洲Av高清一区二区三区| 在线看片免费人成视久网| 亚洲va中文字幕无码久久| 丰满妇女做a级毛片免费观看 | 美女露隐私全部免费直播| 一区二区无码免费视频网站 | 精品久久8x国产免费观看| 无码人妻精品一二三区免费| 亚洲最大福利视频网站| 国内永久免费crm系统z在线| 又大又黄又粗又爽的免费视频| 亚洲国产无线乱码在线观看| 成年女人男人免费视频播放| 国内精品久久久久影院亚洲| 日韩亚洲国产高清免费视频| 亚洲精品熟女国产|