所有的
編程語(yǔ)言我都討厭。曾經(jīng)我想自創(chuàng)一門語(yǔ)言,但我沒搞明白到底需要一門什么語(yǔ)言,所以也從未開始過。 許多時(shí)候,你沒法選擇使用哪種語(yǔ)言。不管我在用哪種語(yǔ)言,我都嘗試去接受它的優(yōu)點(diǎn)和缺點(diǎn)。
Java
喜歡Java的人肯定喜歡打字。我指的就是敲打鍵盤上的鍵。你得不斷地重復(fù)又重復(fù)。
設(shè)計(jì)Java系統(tǒng)的人是個(gè)瘋子,他解決問題的方式就是,設(shè)計(jì)模式。如果你把設(shè)計(jì)模式看作是這個(gè)語(yǔ)言中解決問題的一種方式,那么你會(huì)發(fā)現(xiàn)Java里有許多這樣的設(shè)計(jì)模式。
另一方面,Sun的這些家伙的確是費(fèi)了點(diǎn)心思在Java規(guī)范上的,這使得它能運(yùn)行在嵌入式系統(tǒng)上,所以這塊我們還是堅(jiān)持在使用它。我很難相信
Python或者C在我的
手機(jī)桌面系統(tǒng)上運(yùn)行。
還有,那些個(gè)目錄又是怎么回事?我必須得使用Eclipse,因?yàn)橹挥兴涝趺刺^那1000個(gè)字長(zhǎng)的路徑名。如果我在應(yīng)用的同一個(gè)目錄下放10個(gè)類,會(huì)不會(huì) 傷害到某些人?
C
C是精確的。當(dāng)我用C寫程序的時(shí)候,如果搞定了,我知道它是靠譜的。它就像是用一把小刷子在畫一幅巨作。在這么詳細(xì)的層面上寫代碼需要一種不同的心態(tài)。當(dāng)你坐下來寫C的時(shí)候,在動(dòng)手之前你就得規(guī)劃好到底怎么寫。否則后面肯定得費(fèi)很多工夫去改。
如果你的經(jīng)驗(yàn)足夠豐富,內(nèi)存泄露這種事就不太會(huì)找上門。它的第二特性——malloc/free總是形影不離。你不能忘了任何一個(gè)。否則就像是忘了沖水或者關(guān)燈。你就這么做就是了。
有句話說得好,如果你打算給房子上漆,一把好刷子可遠(yuǎn)遠(yuǎn)不夠。我猜你肯定想要個(gè)大滾軸。如果讓我寫一整個(gè)應(yīng)用或者系統(tǒng),能不用C的話我肯定不用。
C程序想要進(jìn)行改動(dòng)可得費(fèi)老勁了。當(dāng)我寫算法的時(shí)候,我知道第一遍肯定是不會(huì)對(duì)的,所以我通常都先用Python寫,搞定了之后再翻譯成C的。
C++
它就是個(gè)有string類的C。同時(shí)還有數(shù)組,列表,隊(duì)列等東西,你可以用它們來實(shí)現(xiàn)你想要的。一言以蔽之:別想著自創(chuàng)新模板。這太困難了。除了這個(gè),C++還改良了一下C,用C++你可以寫出非常不錯(cuò)的軟件。它這個(gè)額外的特性使得它可以用于一些大型系統(tǒng)上,只要大家都還遵循同樣的約束的話,難度還不算太大。
JavaScript
這是個(gè)沒人喜歡的語(yǔ)言。不過它喜歡你。當(dāng)你剛開始
學(xué)習(xí)它的時(shí)候,你可能會(huì)寫出一些非常糟糕的代碼,把對(duì)象用作字典,別的對(duì)象作KEY,不過這樣也是OK的,因?yàn)檫@些代碼運(yùn)行起來也沒有什么問題,只要瀏覽器還支持JavaScript就好。
JavaScript沒有連接器,因此所有的代碼都共享一個(gè)命名空間,不過還好大家都知道這一點(diǎn),所以還能一起和諧相處。
CoffeeScirpt
CoffeeScirpt是一個(gè)解釋器,它將那些長(zhǎng)得像
Ruby的奇怪的語(yǔ)言逐行地翻譯成JavaScript。它是一個(gè)擁有所有外來語(yǔ)法的JavaScript——括號(hào),方括號(hào),額外關(guān)鍵字移除。只有代碼的基本含義還保留著。
CoffeeScirpt挺不錯(cuò)的。如果你要寫很多代碼的時(shí)候,它能讓你提高至少25%的效率。你可以一次在屏幕上看到更多行的代碼。
當(dāng)你用CoffeeScript寫代碼的時(shí)候,你得時(shí)刻記住這是要生成JavaScript的。問題就在這。你得先去學(xué)習(xí)JavaScript。項(xiàng)目來的新人都得先學(xué)JavaScript,然后才能學(xué)CoffeeScript,最后才能去學(xué)習(xí)項(xiàng)目代碼。
node.js
我也希望能愛上它。我覺得我給過它機(jī)會(huì)了。它的回調(diào)讓我無法忍受。我知道會(huì)有這么一天,因?yàn)槟硞€(gè)原因,其中一個(gè)回調(diào)并沒有出現(xiàn),然后我的應(yīng)用就會(huì)堵在那一直等待。真是要了命了。
還有一點(diǎn)就是,它幾乎沒有內(nèi)建任何東西。如果你要做某件事情,總是會(huì)有一大堆模塊來實(shí)現(xiàn)這個(gè)功能的。該選哪個(gè)呢?如果出現(xiàn)問題了,哪個(gè)模塊會(huì)有人來支持?
Scala
Scala是一門函數(shù)式,強(qiáng)類型的語(yǔ)言,它會(huì)編譯成JVM代碼。
我是在
工作中學(xué)的Scala。有一家初創(chuàng)公司的生產(chǎn)系統(tǒng)用的是它,我是在后期才加入他們的。
這讓我看到了Scala丑陋的一面:類型推導(dǎo)。類型推薦被它用到了極致。每個(gè)對(duì)象都有類型,不過想確定它是什么類型的,你得檢查不同分層上的好幾個(gè)文件才行。Scala也繼承了Java的文件夾的壞毛病,因此你要查找某個(gè)類型的話得進(jìn)入好幾層目錄才能找到對(duì)應(yīng)的那個(gè)文件。
簡(jiǎn)而言之,Scala是極好的——對(duì)于那些最初的開發(fā)人員而言。新加入的成員為了熟悉現(xiàn)有的代碼,得有一個(gè)很長(zhǎng)的學(xué)習(xí)曲線。
Erlang
Erlang也是我曾經(jīng)想愛上的一位。我真的努力了。它是一門美麗的函數(shù)式語(yǔ)言,它可以寫出很精致的小模塊,它們以一種精確的方式進(jìn)行通信,你的系統(tǒng)可以運(yùn)行10年以上,因?yàn)樗芴幚砦粗獑栴},如果必要的話還會(huì)重啟,然后繼續(xù)運(yùn)行。
不過它的結(jié)構(gòu)太復(fù)雜了。開發(fā)似乎要停留在伯克利發(fā)明socket的那個(gè)年代。當(dāng)前時(shí)代所需的東西幾乎一樣都沒有。為什么開發(fā)一個(gè)簡(jiǎn)單的WEB服務(wù)需要費(fèi)這么大的工夫?
Go
Go很容易學(xué)習(xí),對(duì)于新人而言也是如此。它使用40年前的語(yǔ)言概念來構(gòu)建一個(gè)健壯的異步系統(tǒng),但它讓你能像寫同步代碼一樣編程。你可以不費(fèi)吹灰之力寫出1000個(gè)可以安全工作的線程。
在庫(kù)支持方面它仍需要改進(jìn)。當(dāng)我想做某事的時(shí)候,該用哪個(gè)庫(kù)——github上2011年的那個(gè),還是2013年開始的那個(gè)半成品?一個(gè)是官方主頁(yè)鏈接的,不過它的官方主頁(yè)看起來并不是最新的。好吧,我覺得我還是自己寫一個(gè)吧。。。
還有,為什么追加元素到數(shù)組里也這么費(fèi)勁?
Python
在Python里,不管你想做什么都會(huì)有一個(gè)對(duì)應(yīng)的庫(kù),如果你用的是Linux,它絕對(duì)是不二選擇,因?yàn)樗梢砸绘I安裝。
如果你想做些數(shù)字處理或者科學(xué)運(yùn)算,選擇Python吧,你值得擁有。
Python中的字符串即可能是文本的也可能是二進(jìn)制的,因此你得上來就學(xué)習(xí)下文本編碼的東東。
Python 3
Python 3和Python有許多共同的特性,不過它卻是門不同的語(yǔ)言。由于它比較新,因此支持的并不是很好。我也想使用它,不過總會(huì)有那么一個(gè)庫(kù),它是只支持Python 2的。
雖然很早之前就成功裝過這兩個(gè)軟件了。但是前陣子重裝了系統(tǒng)再裝這兩個(gè)軟件時(shí)卻發(fā)現(xiàn)我又把破解的方法給忘了。后來從歷史文檔中搜索了好久才得到解決。想想這些還是需要總結(jié),事情多了,難免忘記。也分享給需要的童鞋們。
LR11的破解方法
1)退出程序,把下載文件中的lm70.dll和mlr5lprg.dll覆蓋掉..\HP\LoadRunner\bin下的這兩個(gè)文件
2)注意,win7的話一定要以管理員身份運(yùn)行啟動(dòng)程序,啟動(dòng)后,點(diǎn)擊 configuration->loadrunner license,此時(shí)可能會(huì)有兩個(gè)許可證信息存在,退出程序,點(diǎn)擊deletelicense.exe文件,來刪除剛才得許可證信息(即時(shí)原來沒有l(wèi)isense最好也運(yùn)行一下)
3)再次打開程序, configuration->loadrunner license->new license,在彈出的輸入框中輸入license序列號(hào)AEABEXFR-YTIEKEKJJMFKEKEKWBRAUNQJU-KBYGB,點(diǎn)擊確定,驗(yàn)證通過后,則破解成功!
QTP11的破解方法
1)安裝成功后,手工創(chuàng)建:C:\Program Files\Common Files\Mercury Interactive下,
建立文件夾License Manager(這個(gè)很重要,必須要?jiǎng)?chuàng)建)
2)拷貝破解文件mgn-mqt82.exe至第一步創(chuàng)建的目錄下。
3)運(yùn)行破解文件,提示在C:\Program Files\Common Files\Mercury Interactive下創(chuàng)建了lservrc文件
4)用記事本打開lservrc,拷貝第一個(gè)#號(hào)前的一大串字符串。運(yùn)行
QTP,輸入這串字符
5)安裝QTP的
功能測(cè)試許可服務(wù)器安裝程序(打開qtp11的安裝包里邊的)
6)刪掉SafeNet Sentinel目錄(C:\ProgramData\SafeNet Sentinel)
7)運(yùn)行\(zhòng)HP\QuickTest Professional\bin中的instdemo.exe
通過一定的工具結(jié)合相應(yīng)的測(cè)試方法,對(duì)部署的系統(tǒng)應(yīng)用進(jìn)行測(cè)試,發(fā)現(xiàn)系統(tǒng)應(yīng)用內(nèi)部存在的代碼邏輯問題及應(yīng)用部署的機(jī)器硬件資源瓶頸問題及應(yīng)用部署架構(gòu)存在架構(gòu)錯(cuò)誤問題,如:網(wǎng)絡(luò)端、客戶端、服務(wù)端搭建的架構(gòu)問題;
負(fù)載測(cè)試:是一個(gè)分析軟件應(yīng)用程序和支撐架構(gòu)、模擬真實(shí)環(huán)境的使用,從而來確定能夠接收的性能過;
壓力測(cè)試(Stress Testing):是通過確定一個(gè)系統(tǒng)的瓶頸或者不能接收的性能點(diǎn),來獲得系統(tǒng)能提供的最大服務(wù)級(jí)別的測(cè)試;
性能測(cè)試的目的:
性能測(cè)試的目的主要體現(xiàn)在三個(gè)方面:以真實(shí)的業(yè)務(wù)為依據(jù),選擇有代表性的、關(guān)鍵的業(yè)務(wù)操作設(shè)計(jì)測(cè)試案例,以評(píng)價(jià)系統(tǒng)的當(dāng)前性能;當(dāng)擴(kuò)展應(yīng)用程序的功能或者新的應(yīng)用程序?qū)⒁徊渴饡r(shí),負(fù)載測(cè)試會(huì)幫助確定系統(tǒng)是否還能夠處理期望的用戶負(fù)載,以預(yù)測(cè)系統(tǒng)的未來性能;通過模擬成百上千個(gè)用戶,重復(fù)執(zhí)行和運(yùn)行測(cè)試,可以確認(rèn)性能瓶頸并優(yōu)化和調(diào)整應(yīng)用,目的在于尋找到瓶頸問題;
項(xiàng)目開發(fā)周期:初始時(shí)刻,項(xiàng)目更多關(guān)注的是功能實(shí)現(xiàn),此時(shí)
功能測(cè)試顯得尤為重要,測(cè)試的提前介入,可以提前預(yù)測(cè)風(fēng)險(xiǎn),減少項(xiàng)目開發(fā)周期、節(jié)約開發(fā)成本;功能測(cè)試后的階段,個(gè)人認(rèn)為應(yīng)該是性能測(cè)試(試想,如果一個(gè)項(xiàng)目連功能都實(shí)現(xiàn)不了,更何談性能測(cè)試);在功能完畢之后,引入性能測(cè)試,通過性能測(cè)試對(duì)開發(fā)項(xiàng)目潛在的問題進(jìn)行排查(功能測(cè)試,僅僅是幾個(gè)人或者幾十個(gè)人簡(jiǎn)單的對(duì)應(yīng)用功能的一個(gè)測(cè)試,對(duì)于應(yīng)用真正上線后的大量用戶使用,應(yīng)用存在的潛在風(fēng)險(xiǎn),并不能做很好的預(yù)估,尤其是當(dāng)前空前的競(jìng)爭(zhēng)壓力下,應(yīng)用上線后的失敗,很可能導(dǎo)致整個(gè)項(xiàng)目的失敗;例如:12306訂票網(wǎng)站,使用量之大,可能全世界前所未有,調(diào)動(dòng)全國(guó)人力去測(cè)試應(yīng)用性能問題,肯定是不可能的。如果事先不經(jīng)過性能測(cè)試,貿(mào)然上線,在如此之多的用戶使用情況下,系統(tǒng)崩潰將是怎樣的一種后果。);
案例分享:編者曾經(jīng)從事過一個(gè)項(xiàng)目,伴隨項(xiàng)目的始終。前期階段,由于測(cè)試提前介入,以及項(xiàng)目開發(fā)采用的
敏捷開發(fā)方式,項(xiàng)目很快在不到半年的時(shí)間內(nèi),功能近乎完美完成。項(xiàng)目經(jīng)理本著穩(wěn)妥起見,引入性能測(cè)試,對(duì)項(xiàng)目潛在的風(fēng)險(xiǎn)進(jìn)行評(píng)估,然后就搭建了一套模擬環(huán)境,專用于性能測(cè)試,搭建的模擬環(huán)境30用戶并發(fā)運(yùn)行,項(xiàng)目一點(diǎn)問題沒有,進(jìn)一步提升并發(fā)用戶數(shù),各種問題接踵而來;經(jīng)過系統(tǒng)調(diào)優(yōu)后(發(fā)布的應(yīng)用系統(tǒng)參數(shù)等),部分問題解決;為了進(jìn)一步測(cè)試實(shí)際情況下存在問題,性能測(cè)試環(huán)境由模擬環(huán)境切到了生產(chǎn)環(huán)境上,此時(shí)是大量用戶下的并發(fā),部分業(yè)務(wù)是沒有問題的,但是更多的問題是集中在涉及到
工作流的一些業(yè)務(wù)場(chǎng)景上,后臺(tái)日志各種報(bào)錯(cuò);通過抓取后臺(tái)日志,對(duì)問題進(jìn)行定位分析,很快排查解決了代碼開發(fā)中存在的一些邏輯問題;代碼修復(fù)后重新上線,問題已基本不存在了;項(xiàng)目也很快結(jié)束,大大的縮短了項(xiàng)目開發(fā)周期、節(jié)約了開發(fā)成功、更好的適用于用戶;
性能測(cè)試注意點(diǎn):
錄制腳本盡量模擬實(shí)際用戶操作,在場(chǎng)景設(shè)計(jì)時(shí),盡量與實(shí)際場(chǎng)景一致,對(duì)于用戶使用比較多的業(yè)務(wù),應(yīng)著重關(guān)注;
性能測(cè)試盡可能在實(shí)際生產(chǎn)環(huán)境上進(jìn)行,普通模擬環(huán)境并不能真正發(fā)現(xiàn)實(shí)際生產(chǎn)環(huán)境下,應(yīng)用存在的問題,但是并非棄用模擬環(huán)境;
性能測(cè)試,對(duì)于應(yīng)用系統(tǒng)部署的環(huán)境上,可能需要部署一些系統(tǒng)性能監(jiān)控軟件,在軟件的選取上,盡可能降低軟件自身運(yùn)行對(duì)系統(tǒng)性能的影響;
性能測(cè)試,特別是應(yīng)用與
數(shù)據(jù)庫(kù)交互的業(yè)務(wù)操作上,需要提前預(yù)制符合性能測(cè)試業(yè)務(wù)需求的數(shù)據(jù),在此基礎(chǔ)上,盡量讓環(huán)境測(cè)試環(huán)境可多次重復(fù)使用,這就要求數(shù)據(jù)、應(yīng)用可還原;
性能測(cè)試技能掌握要求:
測(cè)試環(huán)境搭建,環(huán)境搭建不僅僅是性能測(cè)試所需要具備的技能,也是測(cè)試人員所需要具備的基本技能;很多測(cè)試,包括應(yīng)用的安裝卸載,都需要測(cè)試人員具備這一技能;
應(yīng)用搭建使用協(xié)議的了解,很多情況下,性能測(cè)試人員需要錄制測(cè)試腳本,這就要測(cè)試人員對(duì)應(yīng)用采用的協(xié)議有充分的了解;
服務(wù)器架構(gòu)的了解,單一的一臺(tái)服務(wù)器、多臺(tái)服務(wù)器情況下的集群架構(gòu)等,了解服務(wù)器架構(gòu),可以為性能測(cè)試人員初期性能調(diào)優(yōu)提供幫助;
操作系統(tǒng)機(jī)能的掌握,特別是
Linux操作系統(tǒng)的了解,當(dāng)前大多數(shù)的應(yīng)用部署在Linux操作系統(tǒng)之上,性能測(cè)試人員需要掌握操作系統(tǒng)知識(shí)這一基礎(chǔ)技能;
數(shù)據(jù)庫(kù)知識(shí),面對(duì)大數(shù)據(jù)時(shí)代,數(shù)據(jù)庫(kù)機(jī)能的掌握不僅僅可以為性能測(cè)試服務(wù),還可以為你今后的華麗轉(zhuǎn)型,提供良好保障,華麗的DBA;
良好的編碼思量。基礎(chǔ)的編碼知識(shí),對(duì)于編碼的了解,可以為你今后沖擊高級(jí)性能測(cè)試工程師提供有力保障,一個(gè)高級(jí)性能測(cè)試工程師,應(yīng)當(dāng)具有性能調(diào)優(yōu)這一技能,編碼就顯得尤為重要;
對(duì)于新技術(shù)、新思想的一種追求與掌握;
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=
jdbc.driver=不同的數(shù)據(jù)庫(kù)廠商驅(qū)動(dòng),此處不一一列舉
接下來,詳細(xì)配置代碼如下:
<beans> <!-- picks up and registers AppConfig as a bean definition --> <context:component-scan base-package="com.acme"/> <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/> <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> </beans> |
DBCP連接池
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> C3P0 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driverClassName}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <context:property-placeholder location="jdbc.properties"/> proxool <bean id="dataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driverClassName}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <context:property-placeholder location="jdbc.properties"/> |
當(dāng)然還有Druid 、DBPool 、Jakarta DBCP 等
一、多路徑解釋 多路徑,顧名思義就是有多種選擇的路徑。在SAN或IPSAN環(huán)境,主機(jī)和存儲(chǔ)之間外加了光纖交換機(jī),這就導(dǎo)致主機(jī)和存儲(chǔ)之間交換速度和效率增強(qiáng),一條路徑肯定是不行的,也是不安全不穩(wěn)定的。多路徑就是要來解決從主機(jī)到磁盤之間最快,最高效的問題。主要實(shí)現(xiàn)如下幾個(gè)功能
故障的切換和恢復(fù)
IO流量的負(fù)載均衡
磁盤的虛擬化
多路徑之前一直是存儲(chǔ)廠商負(fù)責(zé)解決,竟來被拆分出來單獨(dú)賣錢了。
構(gòu)架基本是這樣的:存儲(chǔ),多路徑軟件,光纖交換機(jī),主機(jī),主機(jī)系統(tǒng)。
二、LINUX下的multipath
1、查看是否自帶安裝?
[root@web2 multipath]# rpm -qa|grep device
device-mapper-1.02.39-1.el5
device-mapper-1.02.39-1.el5
device-mapper-multipath-0.4.7-34.el5
device-mapper-event-1.02.39-1.el5
[root@web2 multipath]#
2、安裝
rpm -ivh device-mapper-1.02.39-1.el5.rpm #安裝映射包
rpm -ivh device-mapper-multipath-0.4.7-34.el5.rpm #安裝多路徑包
外加加入開機(jī)啟動(dòng)
chkconfig –level 2345 multipathd on #設(shè)置成開機(jī)自啟動(dòng)multipathd
lsmod |grep dm_multipath #來檢查安裝是否正常
3、配置
# on the default devices. blacklist { devnode "^(ram|raw|loop|fd|md|dm-|sr|sr|scd|st)[0-9]*" devnode "^hd[a-z]" } devices { device { vendor "HP" path_grouping_policy multibus features "1 queue_if_no_path" path_checker readsector() failback immediate } }<br><br>完整的配置如下: blacklist { devnode "^sda" } defaults { user_friendly_names no } multipaths { multipath { wwid 14945540000000000a67854c6270b4359c66c272e2f356321 alias iscsi-dm0 path_grouping_policy multibus path_checker tur path_selector "round-robin 0" } multipath { wwid 14945540000000000dcca2eda91d70b81edbcfce2357f99ee alias iscsi-dm1 path_grouping_policy multibus path_checker tur path_selector "round-robin 0" } multipath { wwid 1494554000000000020f763489c165561101813333957ed96 alias iscsi-dm2 path_grouping_policy multibus path_checker tur path_selector "round-robin 0" } multipath { wwid 14945540000000000919ca813020a195422ba3663e1f03cc3 alias iscsi-dm3 path_grouping_policy multibus path_checker tur path_selector "round-robin 0" } } devices { device { vendor "iSCSI-Enterprise" product "Virtual disk" path_grouping_policy multibus getuid_callout "/sbin/scsi_id -g -u -s /block/%n" path_checker readsector0 path_selector "round-robin 0" } } |
4、命令 [root@web2 ~]# multipath -h multipath-tools v0.4.7 (03/12, 2006) Usage: multipath [-v level] [-d] [-h|-l|-ll|-f|-F|-r] [-p failover|multibus|group_by_serial|group_by_prio] [device] -v level verbosity level 0 no output 1 print created devmap names only 2 default verbosity 3 print debug information -h print this usage text -b file bindings file location -d dry run, do not create or update devmaps -l show multipath topology (sysfs and DM info) -ll show multipath topology (maximum info) -f flush a multipath device map -F flush all multipath device maps -r force devmap reload -p policy force all maps to specified policy : failover 1 path per priority group multibus all paths in 1 priority group group_by_serial 1 priority group per serial group_by_prio 1 priority group per priority lvl group_by_node_name 1 priority group per target node device limit scope to the device's multipath (udev-style $DEVNAME reference, eg /dev/sdb or major:minor or a device map name) [root@web2 ~]# |
5、啟動(dòng)關(guān)閉
# /etc/init.d/multipathd start #開啟mulitipath服務(wù)
service multipath start
service multipath restart
service multipath shutdown
6、如何獲取wwid
1、
[root@vxfs01 ~]# cat /var/lib/multipath/bindings
# Multipath bindings, Version : 1.0
# NOTE: this file is automatically maintained by the multipath program.
# You should not need to edit this file in normal circumstances.
#
# Format:
# alias wwid
#
mpath0 36006016051d50e0035744871c912de11
mpath1 36006016051d50e0034744871c912de11
mpath2 36006016051d50e0032744871c912de11
mpath3 36006016051d50e0039744871c912de11
mpath4 36006016051d50e003a744871c912de11
2、
[root@vxfs01 ~]# multipath -v3 |grep 3600
sdb: uid = 36006016051d50e003a744871c912de11 (callout)
sdc: uid = 36006016051d50e003a744871c912de11 (callout)
sdd: uid = 36006016051d50e003a744871c912de11 (callout)
sde: uid = 36006016051d50e003a744871c912de11 (callout)
36006016051d50e003a744871c912de11 1:0:0:0 sdb 8:16 0 [undef][ready] DGC,RAI
36006016051d50e003a744871c912de11 1:0:1:0 sdc 8:32 1 [undef][ready] DGC,RAI
36006016051d50e003a744871c912de11 2:0:0:0 sdd 8:48 1 [undef][ready] DGC,RAI
36006016051d50e003a744871c912de11 2:0:1:0 sde 8:64 0 [undef][ready] DGC,RAI
Found matching wwid [36006016051d50e003a744871c912de11] in bindings file.
Java的訪問控制權(quán)限相比于C++等語(yǔ)言可能稍微復(fù)雜一點(diǎn),不過也不難理解。Java的訪問控制權(quán)限分為兩塊——“類或接口的訪問控制權(quán)限”與“變量和方法的訪問控制權(quán)限”。
1.類或接口的訪問控制權(quán)限
類或接口的訪問控制權(quán)限是指能不能用該類建立對(duì)象,接口能不能被實(shí)現(xiàn)等等。能夠修飾類或接口的訪問控制權(quán)限的修飾符(modifier)只有兩個(gè)——public和friendly.不過,值得一說的是friendly并不是Java的關(guān)鍵字,它只是一個(gè)習(xí)慣叫法,指的是“沒有寫訪問控制權(quán)限修飾符”的情況。
public修飾的類或接口在同一個(gè)包中的任何一個(gè)類中都可以被訪問。不同包呢?當(dāng)然能訪問啦,否則引包機(jī)制不就失效了嘛(因?yàn)橐喈?dāng)于拿到了一個(gè)包的public類或接口)。
friendly修飾的類或接口在同一個(gè)包中的任何一個(gè)類中都可以被訪問(和public相同),不能被不同包中的類訪問。
總結(jié):類或接口的訪問控制權(quán)限分為“包中”和“包外”。無論修飾符(modifier)是什么,在“包中”均可訪問。對(duì)于“包外”,public修飾的類或接口可以被訪問,friendly修飾的類或接口不能被訪問。
2.變量和方法的訪問控制權(quán)限
變量和方法的訪問控制權(quán)限的修飾符(modifier)有四個(gè)——public,protected,friendly和private.
變量和方法在本類(定義該變量或方法的類)中不論訪問控制權(quán)限修飾符是什么,均可被訪問(這里先不考慮“靜態(tài)”的情況)。那么接下來只研究類外。類外也分“包內(nèi)”和“包外”,接下來就從這兩方面說起,并且研究“包外”時(shí)只考慮引入的包中的public類,因?yàn)閒riendly的類連直接被訪問都做不到,何談訪問變量和方法。
public修飾的變量和方法在“包內(nèi)”和“包外”均可被訪問。
protected修飾的變量和方法在“包內(nèi)”可以被訪問,在“包外”只能被子類訪問。
friendly修飾的變量和方法在“包內(nèi)”可以被訪問,在“包外”不能被訪問。
private修飾的變量和方法在“包內(nèi)”或“包外”均不能被訪問。
總結(jié):對(duì)于“類外”,public,protected,friendly和private的嚴(yán)格性逐漸遞增。public可以說沒限制,protected剝奪了“包外”非子類的訪問能力,friendly在protected基礎(chǔ)上進(jìn)一步剝奪了“包外”子類的訪問能力,至此“包外”的訪問能力全無;private更嚴(yán)格,它在friendly基礎(chǔ)上更是一下剝奪了“包內(nèi)”的訪問能力。
總的來說,看某個(gè)成員能否被訪問要分兩步:1.根據(jù)所在類的訪問控制權(quán)限看該類能否被訪問;2.根據(jù)該成員的訪問控制權(quán)限判斷取得所在類后該成員能否被訪問。
文檔需要全面,實(shí)時(shí)更新,并且易懂。我說的全面是指除了介紹程序的功能外還應(yīng)該覆蓋到代碼中一些重要的地方。對(duì)很多人來說文檔的重要性不言而喻,但很難保持它的及時(shí)性和準(zhǔn)確性。糟糕的文檔的后果通常會(huì)浪費(fèi)更多的資源和時(shí)間。往往都是出于一些錯(cuò)誤的原因而編寫的文檔。
要求文檔的一些原因
有很多原因?qū)е挛覀冃枰帉懳臋n。團(tuán)隊(duì)經(jīng)常會(huì)由于一些制度上的要求而編寫文檔,或者就是純粹出于無知。下面是一些編寫文檔的錯(cuò)誤的理由:
有人認(rèn)為文檔和項(xiàng)目的成敗息息相關(guān)。
文檔能夠證明某些人的存在。
需求方除了文檔也不知道要什么好
要你提供文檔的人也就是求個(gè)安心,知道事情都OK了
文檔都是過時(shí)的
軟件文檔的一個(gè)主要的問題就是它通常都不是最新的。代碼的某個(gè)部分可能發(fā)生了改動(dòng),但是文檔卻體現(xiàn)不出這個(gè)情況。這句話適用于幾乎所有的文檔,影響最大的其實(shí)還是需求和
測(cè)試用例。不管你多努力,文檔的過期無可避免。
文檔對(duì)誰(shuí)有用?
取決于不同的受眾,文檔的類型和格式也會(huì)相應(yīng)地有所不同。開發(fā)人員,測(cè)試人員,客戶,主管,最終用戶都是文檔的最大的潛在用戶。
開發(fā)人員
開發(fā)人員不應(yīng)該依賴于文檔,因?yàn)樗鼈兺ǔ6际沁^時(shí)的。除此之外,沒有什么文檔能比代碼本身更能提供詳細(xì)以及最新的信息了。如果你想知道某個(gè)方法做了些什么,看下這個(gè)方法吧。不確定某個(gè)類是干嘛的?看一眼它。通常只有代碼寫的太差了才需要給它添加文檔。
使用代碼本身作為文檔,這并不代表不需要其它的文檔了。關(guān)鍵是要避免冗余。如果看一下代碼就能獲取到系統(tǒng)的詳細(xì)信息,那么還可以有一些其它的文檔來提供快速導(dǎo)讀以及更高層面的一個(gè)概述的功能。代碼本身的文檔是回答不了這個(gè)系統(tǒng)是干嘛的或者這個(gè)系統(tǒng)用到了什么技術(shù)啊這種類型的問題。大多數(shù)情況下,對(duì)于開發(fā)人員而言,一個(gè)簡(jiǎn)單的README.md就足夠他快速入門的了。像項(xiàng)目描述,環(huán)境配置,安裝,構(gòu)建及打包指令這些東西對(duì)項(xiàng)目的新成員來說非常有用。但那之后,代碼就是你的圣經(jīng)。產(chǎn)品代碼提供了所有需要的詳細(xì)信息,而測(cè)試代碼則是作為產(chǎn)品代碼的內(nèi)在意圖的一個(gè)描述。測(cè)試用例就是可執(zhí)行的文檔,而TDD(測(cè)試驅(qū)動(dòng)開發(fā))就是實(shí)現(xiàn)它的最常見的方式。
假設(shè)你用了某種持續(xù)集成的方式,如果測(cè)試-文檔(這里測(cè)試就是文檔,文檔也是測(cè)試)中有一部分不對(duì)了,這個(gè)用例會(huì)執(zhí)行失敗,它將會(huì)很快得到修復(fù)。持續(xù)集成解決了測(cè)試-文檔不正確的問題,不過它不能保證所有功能都是有文檔的。由于這個(gè)原因(當(dāng)然也有其它原因)測(cè)試-文檔應(yīng)當(dāng)用TDD的方式來創(chuàng)建。如果在代碼開發(fā)前,所有的功能都定義成測(cè)試用例,那么測(cè)試用例就能作為開發(fā)人員的一個(gè)完備的最新的文檔了。
那團(tuán)隊(duì)的其它成員怎么辦?測(cè)試人員,客戶,主管,還有其它非碼農(nóng)呢,他們可能無法從產(chǎn)品和測(cè)試的代碼中獲取到所需要的信息。
測(cè)試人員
最常見的兩種測(cè)試就是
黑盒測(cè)試和
白盒測(cè)試。這個(gè)區(qū)分很重要,因?yàn)樗鼘y(cè)試人員也分成了兩類,一撥是知道怎么寫代碼的,至少是能讀懂代碼的(白盒測(cè)試),另一撥是不懂代碼的(黑盒測(cè)試)。有的時(shí)候測(cè)試人員也兩樣都干。不過一般而言,測(cè)試都是不懂代碼的,因此對(duì)開發(fā)人員有用的文檔對(duì)他們來說是沒意義的。如果說要從代碼中剝離出文檔的話,
單元測(cè)試可不是什么合適的東西。這就是BDD(行為驅(qū)動(dòng)開發(fā),Behavior Driven Development)存在的價(jià)值了。它能為非開發(fā)人員提供所需的文檔,但同時(shí)還兼?zhèn)銽DD和自動(dòng)化的優(yōu)點(diǎn)。
客戶
客戶需要能夠給系統(tǒng)增加新的功能,同時(shí)他們也需要獲取到關(guān)于當(dāng)前系統(tǒng)的重要信息。給他們的文檔可不能太技術(shù)了(代碼當(dāng)然不行),同時(shí)也得是最新的。行為驅(qū)動(dòng)開發(fā)(BDD,Behavior Driven Development)的故事和場(chǎng)景應(yīng)該是提供這類文檔的最佳方式了。它能夠作為驗(yàn)收標(biāo)準(zhǔn)(在代碼開發(fā)前),還可以反復(fù)的執(zhí)行,同時(shí)還能用自然語(yǔ)言編寫,這使得BDD不僅僅能夠保證文檔是最新的,同時(shí)它對(duì)那些不想看代碼的人來說也非常有用。
可執(zhí)行的文檔
文檔是軟件不可或缺的一部分。正如軟件的其它部分一樣,它也得經(jīng)常進(jìn)行測(cè)試,這樣才能保證它是準(zhǔn)確的并且是最新的。實(shí)現(xiàn)這個(gè)最有效的方法就是將這個(gè)可執(zhí)行的文檔能夠集成到你的持續(xù)集成系統(tǒng)里面。TDD是這個(gè)方向的不二選擇。從較低層面來看的話,單元測(cè)試就非常適合作為這個(gè)文檔。另一方面來說的話,在功能層面來說BDD是一個(gè)很好的方式,它可以使用自然語(yǔ)言來進(jìn)行描述,這保證了文檔的可讀性。
XMLHttpRequest Level 2 添加了一個(gè)新的接口——FormData。利用 FormData 對(duì)象,我們可以通過 JavaScript 用一些鍵值對(duì)來模擬一系列表單控件,我們還可以使用 XMLHttpRequest 的 send() 方法來異步的提交表單。與普通的 Ajax 相比,使用 FormData 的最大優(yōu)點(diǎn)就是我們可以異步上傳二進(jìn)制文件。
創(chuàng)建一個(gè)FormData對(duì)象
你可以先創(chuàng)建一個(gè)空的 FormData 對(duì)象,然后使用 append() 方法向該對(duì)象里添加字段,如下:
var oMyForm = new FormData(); oMyForm.append("username", "Groucho"); oMyForm.append("accountnum", 123456); // 數(shù)字123456被立即轉(zhuǎn)換成字符串"123456" // fileInputElement中已經(jīng)包含了用戶所選擇的文件 oMyForm.append("userfile", fileInputElement.files[0]); var oFileBody = "<a id="a"><b id="b">hey!</b></a>"; // Blob對(duì)象包含的文件內(nèi)容 var oBlob = new Blob([oFileBody], { type: "text/xml"}); oMyForm.append("webmasterfile", oBlob); var oReq = new XMLHttpRequest(); oReq.open("POST", "http://foo.com/submitform.php"); oReq.send(oMyForm); |
注:字段 "userfile" 和 "webmasterfile" 的值都包含了一個(gè)文件。通過 FormData.append() 方法賦給字段 "accountnum" 的數(shù)字被自動(dòng)轉(zhuǎn)換為字符(字段的值可以是一個(gè) Blob 對(duì)象,F(xiàn)ile對(duì)象或者字符串,剩下其他類型的值都會(huì)被自動(dòng)轉(zhuǎn)換成字符串)。
在該例子中,我們創(chuàng)建了一個(gè)名為 oMyForm 的 FormData 對(duì)象,該對(duì)象中包含了名為"username","accountnum","userfile" 以及 "webmasterfile" 的字段名,然后使用XMLHttpRequest的 send() 方法把這些數(shù)據(jù)發(fā)送了出去。"webmasterfile" 字段的值不是一個(gè)字符串,還是一個(gè) Blob 對(duì)象。
使用HTML表單來初始化一個(gè)FormData對(duì)象
可以用一個(gè)已有的 form 元素來初始化 FormData 對(duì)象,只需要把這個(gè) form 元素作為參數(shù)傳入 FormData 構(gòu)造函數(shù)即可:
var newFormData = new FormData(someFormElement);
例如:
var formElement = document.getElementById("myFormElement");
var oReq = new XMLHttpRequest();
oReq.open("POST", "submitform.php");
oReq.send(new FormData(formElement));
你還可以在已有表單數(shù)據(jù)的基礎(chǔ)上,繼續(xù)添加新的鍵值對(duì),如下:
var formElement = document.getElementById("myFormElement");
formData = new FormData(formElement);
formData.append("serialnumber", serialNumber++);
oReq.send(formData);
你可以通過這種方式添加一些不想讓用戶編輯的固定字段,然后再發(fā)送. 使用FormData對(duì)象發(fā)送文件
你還可以使用 FormData 來發(fā)送二進(jìn)制文件.首先在 HTML 中要有一個(gè)包含了文件輸入框的 form 元素:
<form enctype="multipart/form-data" method="post" name="fileinfo"> <label>Your email address:</label> <input type="email" autocomplete="on" autofocus name="userid" placeholder="email" required size="32" maxlength="64" /><br /> <label>Custom file label:</label> <input type="text" name="filelabel" size="12" maxlength="32" /><br /> <label>File to stash:</label> <input type="file" name="file" required /> </form> <div id="output"></div> <a href="javascript:sendForm()">Stash the file!</a> |
然后你就可以使用下面的代碼來異步的上傳用戶所選擇的文件:
function sendForm() { var oOutput = document.getElementById("output"); var oData = new FormData(document.forms.namedItem("fileinfo")); oData.append("CustomField", "This is some extra data"); var oReq = new XMLHttpRequest(); oReq.open("POST", "stash.php", true); oReq.onload = function(oEvent) { if (oReq.status == 200) { oOutput.innerHTML = "Uploaded!"; } else { oOutput.innerHTML = "Error " + oReq.status + " occurred uploading your file.<br \/>"; } }; oReq.send(oData); } |
你還可以不借助 HTML 表單,直接向 FormData 對(duì)象中添加一個(gè) File 對(duì)象或者一個(gè) Blob 對(duì)象:
data.append("myfile", myBlob);
如果 FormData 對(duì)象中的某個(gè)字段值是一個(gè) Blob 對(duì)象,則在發(fā)送 HTTP 請(qǐng)求時(shí),代表該 Blob 對(duì)象所包含文件的文件名的 "Content-Disposition" 請(qǐng)求頭的值在不同的瀏覽器下有所不同,F(xiàn)irefox使用了固定的字符串"blob",而 Chrome 使用了一個(gè)隨機(jī)字符串。
你還可以使用 jQuery 來發(fā)送 FormData,但必須要正確的設(shè)置相關(guān)選項(xiàng):
var fd = new FormData(document.getElementById("fileinfo")); fd.append("CustomField", "This is some extra data"); $.ajax({ url: "stash.php", type: "POST", data: fd, processData: false, // 告訴jQuery不要去處理發(fā)送的數(shù)據(jù) contentType: false // 告訴jQuery不要去設(shè)置Content-Type請(qǐng)求頭 }); |
瀏覽器兼容性
在做
單元測(cè)試時(shí),
代碼覆蓋率常常被拿來作為衡量測(cè)試好壞的指標(biāo),甚至,用代碼覆蓋率來考核測(cè)試任務(wù)完成情況,比如,代碼覆蓋率必須達(dá)到80%或 90%。于是乎,測(cè)試人員費(fèi)盡心思設(shè)計(jì)案例覆蓋代碼。用代碼覆蓋率來衡量,有利也有有弊。本文我們就代碼覆蓋率展開討論,也歡迎同學(xué)們踴躍評(píng)論。
首先,讓我們先來了解一下所謂的“代碼覆蓋率”。我找來了所謂的定義:
代碼覆蓋率 = 代碼的覆蓋程度,一種度量方式。
上面簡(jiǎn)短精悍的文字非常準(zhǔn)確的描述了代碼覆蓋率的含義。而代碼覆蓋程度的度量方式是有很多種的,這里介紹一下最常用的幾種:
1. 語(yǔ)句覆蓋(StatementCoverage)
又稱行覆蓋(LineCoverage),段覆蓋(SegmentCoverage),基本塊覆蓋(BasicBlockCoverage),這是最常用也是最常見的一種覆蓋方式,就是度量被測(cè)代碼中每個(gè)可執(zhí)行語(yǔ)句是否被執(zhí)行到了。這里說的是“可執(zhí)行語(yǔ)句”,因此就不會(huì)包括像C++的頭文件聲明,代碼注釋,空行,等等。非常好理解,只統(tǒng)計(jì)能夠執(zhí)行的代碼被執(zhí)行了多少行。需要注意的是,單獨(dú)一行的花括號(hào){} 也常常被統(tǒng)計(jì)進(jìn)去。語(yǔ)句覆蓋常常被人指責(zé)為“最弱的覆蓋”,它只管覆蓋代碼中的執(zhí)行語(yǔ)句,卻不考慮各種分支的組合等等。假如你的上司只要求你達(dá)到語(yǔ)句覆蓋,那么你可以省下很多功夫,但是,換來的確實(shí)測(cè)試效果的不明顯,很難更多地發(fā)現(xiàn)代碼中的問題。
這里舉一個(gè)不能再簡(jiǎn)單的例子,我們看下面的被測(cè)試代碼:
int foo(int a, int b)
{
return a / b;
}
假如我們的測(cè)試人員編寫如下測(cè)試案例:
TeseCase: a = 10, b = 5
測(cè)試人員的測(cè)試結(jié)果會(huì)告訴你,他的代碼覆蓋率達(dá)到了100%,并且所有測(cè)試案例都通過了。然而遺憾的是,我們的語(yǔ)句覆蓋率達(dá)到了所謂的100%,但是卻沒有發(fā)現(xiàn)最簡(jiǎn)單的
Bug,比如,當(dāng)我讓b=0時(shí),會(huì)拋出一個(gè)除零異常。
正因如此,假如上面只要求測(cè)試人員語(yǔ)句覆蓋率達(dá)到多少的話,測(cè)試人員只要鉆鉆空子,專門針對(duì)如何覆蓋代碼行編寫測(cè)試案例,就很容易達(dá)到主管的要求。當(dāng)然了,這同時(shí)說明了幾個(gè)問題:
1.主管只使用語(yǔ)句覆蓋率來考核測(cè)試人員本身就有問題。
2.測(cè)試人員的目的是為了測(cè)好代碼,鉆如此的空子是缺乏職業(yè)道德的。
3.是否應(yīng)該采用更好的考核方式來考核測(cè)試人員的
工作?
為了尋求更好的考核標(biāo)準(zhǔn),我們必須先了解完代碼覆蓋率到底還有哪些,如果你的主管只知道語(yǔ)句覆蓋,行覆蓋,那么你應(yīng)該主動(dòng)向他介紹還有更多的覆蓋方式。比如:
2. 判定覆蓋(DecisionCoverage)
又稱分支覆蓋(BranchCoverage),所有邊界覆蓋(All-EdgesCoverage),基本路徑覆蓋(BasicPathCoverage),判定路徑覆蓋(Decision-Decision-Path)。它度量程序中每一個(gè)判定的分支是否都被測(cè)試到了。這句話是需要進(jìn)一步理解的,應(yīng)該非常容易和下面說到的條件覆蓋混淆。因此我們直接介紹第三種覆蓋方式,然后和判定覆蓋一起來對(duì)比,就明白兩者是怎么回事了。
3. 條件覆蓋(ConditionCoverage)
它度量判定中的每個(gè)子表達(dá)式結(jié)果true和false是否被測(cè)試到了。為了說明判定覆蓋和條件覆蓋的區(qū)別,我們來舉一個(gè)例子,假如我們的被測(cè)代碼如下:
int foo(int a, int b)
{
if (a < 10 || b < 10) // 判定
{
return 0; // 分支一
}
else
{
return 1; // 分支二
}
}
設(shè)計(jì)判定覆蓋案例時(shí),我們只需要考慮判定結(jié)果為true和false兩種情況,因此,我們?cè)O(shè)計(jì)如下的案例就能達(dá)到判定覆蓋率100%:
TestCaes1: a = 5, b = 任意數(shù)字 覆蓋了分支一
TestCaes2: a = 15, b = 15 覆蓋了分支二
設(shè)計(jì)條件覆蓋案例時(shí),我們需要考慮判定中的每個(gè)條件表達(dá)式結(jié)果,為了覆蓋率達(dá)到100%,我們?cè)O(shè)計(jì)了如下的案例:
TestCase1: a = 5, b = 5 true, true
TestCase4: a = 15, b = 15 false, false
通過上面的例子,我們應(yīng)該很清楚了判定覆蓋和條件覆蓋的區(qū)別。需要特別注意的是:條件覆蓋不是將判定中的每個(gè)條件表達(dá)式的結(jié)果進(jìn)行排列組合,而是只要每個(gè)條件表達(dá)式的結(jié)果true和false測(cè)試到了就OK了。因此,我們可以這樣推論:完全的條件覆蓋并不能保證完全的判定覆蓋。比如上面的例子,假如我設(shè)計(jì)的案例為:
TestCase1: a = 5, b = 15 true, false 分支一
TestCase1: a = 15, b = 5 false, true 分支一
我們看到,雖然我們完整的做到了條件覆蓋,但是我們卻沒有做到完整的判定覆蓋,我們只覆蓋了分支一。上面的例子也可以看出,這兩種覆蓋方式看起來似乎都不咋滴。我們接下來看看第四種覆蓋方式。
4. 路徑覆蓋(PathCoverage)
又稱斷言覆蓋(PredicateCoverage)。它度量了是否函數(shù)的每一個(gè)分支都被執(zhí)行了。 這句話也非常好理解,就是所有可能的分支都執(zhí)行一遍,有多個(gè)分支嵌套時(shí),需要對(duì)多個(gè)分支進(jìn)行排列組合,可想而知,測(cè)試路徑隨著分支的數(shù)量指數(shù)級(jí)別增加。比如下面的測(cè)試代碼中有兩個(gè)判定分支:
int foo(int a, int b)
{
int nReturn = 0;
if (a < 10)
{// 分支一
nReturn += 1;
}
if (b < 10)
{// 分支二
nReturn += 10;
}
return nReturn;
}
對(duì)上面的代碼,我們分別針對(duì)我們前三種覆蓋方式來設(shè)計(jì)測(cè)試案例:
a. 語(yǔ)句覆蓋
TestCase a = 5, b = 5 nReturn = 11
語(yǔ)句覆蓋率100%
b. 判定覆蓋
TestCase1 a = 5, b = 5 nReturn = 11
TestCase2 a = 15, b = 15 nReturn = 0
判定覆蓋率100%
c. 條件覆蓋
TestCase1 a = 5, b = 15 nReturn = 1
TestCase2 a = 15, b = 5 nReturn = 10
條件覆蓋率100%
我們看到,上面三種覆蓋率結(jié)果看起來都很酷!都達(dá)到了100%!主管可能會(huì)非常的開心,但是,讓我們?cè)偃プ屑?xì)的看看,上面被測(cè)代碼中,nReturn的結(jié)果一共有四種可能的返回值:0,1,10,11,而我們上面的針對(duì)每種覆蓋率設(shè)計(jì)的測(cè)試案例只覆蓋了部分返回值,因此,可以說使用上面任一覆蓋方式,雖然覆蓋率達(dá)到了100%,但是并沒有測(cè)試完全。接下來我們來看看針對(duì)路徑覆蓋設(shè)計(jì)出來的測(cè)試案例:
TestCase1 a = 5, b = 5 nReturn = 0
TestCase2 a = 15, b = 5 nReturn = 1
TestCase3 a = 5, b = 15 nReturn = 10
TestCase4 a = 15, b = 15 nReturn = 11
路徑覆蓋率100%
太棒了!路徑覆蓋將所有可能的返回值都測(cè)試到了。這也正是它被很多人認(rèn)為是“最強(qiáng)的覆蓋”的原因了。
還有一些其他的覆蓋方式,如:循環(huán)覆蓋(LoopCoverage),它度量是否對(duì)循環(huán)體執(zhí)行了零次,一次和多余一次循環(huán)。剩下一些其他覆蓋方式就不介紹了。
總結(jié)
通過上面的學(xué)習(xí),我們?cè)倩仡^想想,覆蓋率數(shù)據(jù)到底有多大意義。我總結(jié)了如下幾個(gè)觀點(diǎn),歡迎大家討論:
a. 覆蓋率數(shù)據(jù)只能代表你測(cè)試過哪些代碼,不能代表你是否測(cè)試好這些代碼。(比如上面第一個(gè)除零Bug)
b. 不要過于相信覆蓋率數(shù)據(jù)。
c. 不要只拿語(yǔ)句覆蓋率(行覆蓋率)來考核你的測(cè)試人員。
d. 路徑覆蓋率 > 判定覆蓋 > 語(yǔ)句覆蓋
e. 測(cè)試人員不能盲目追求代碼覆蓋率,而應(yīng)該想辦法設(shè)計(jì)更多更好的案例,哪怕多設(shè)計(jì)出來的案例對(duì)覆蓋率一點(diǎn)影響也沒有。
使用HP
UFT 12.00版本(主要是
GUI測(cè)試)一段時(shí)間,有些小想法,本來是打算回復(fù)給hp相關(guān)人員,奈何郵件一直遭拒,所以暫且先放在這里吧。
關(guān)于HP 的UFT,簡(jiǎn)單做一下評(píng)價(jià),總體來說是一款很好的軟件,極容易上手和使用(這個(gè)也估計(jì)只是我沒有往深入研究),
測(cè)試流程和思路也很清晰,重點(diǎn)是和HP一些其他自動(dòng)化工具,比如Loadrunner,QC可以結(jié)合起來用,堪稱完美。拍完馬屁說點(diǎn)實(shí)際的。
其實(shí)對(duì)于目前所在公司的項(xiàng)目,我一直很猶豫要不要引進(jìn)HP的這款軟件,首先我對(duì)于這款軟件不是很熟悉,當(dāng)然現(xiàn)在這個(gè)理由是可以排除的,對(duì)于這個(gè)軟件的效果怎么樣,我也不確定,之前公司沒有使用這個(gè)軟件,所以也沒有什么積累,一切都要從零開始。明確知道這個(gè)軟件可能在后期的回歸測(cè)試會(huì)減少點(diǎn)人力,但是前期的的腳本錄制,調(diào)試,以及維護(hù),感覺也不是一個(gè)小工程。
學(xué)習(xí)使用HP UFT軟件的過程不算很艱難,網(wǎng)上的資料還算是比較多的,加上采用錄制的模式,只需點(diǎn)點(diǎn)點(diǎn)的就可以了,使用起來還是很輕松的,當(dāng)然也會(huì)遇到一些問題,不過在網(wǎng)上查查資料基本上可以解決大部分。底層的腳本錄制基本上解決的差不多了,開始關(guān)注整個(gè)測(cè)試流程框架,也就是在這個(gè)地方,突然間發(fā)現(xiàn)HPUFT的GUI測(cè)試不靈活,感覺有些死板。
簡(jiǎn)單說就是動(dòng)作Action的執(zhí)行順序只能按你設(shè)定好的跑,由于之前本人是測(cè)試android產(chǎn)品的,有使用過Monkeyrunner相關(guān)的測(cè)試工具,對(duì)于這種按設(shè)定路線走的
自動(dòng)化測(cè)試工具有些不是很習(xí)慣。于是乎,突發(fā)奇思妙想,要是HPUFT的GUI測(cè)試也可以做到這種隨機(jī)的測(cè)試就好了,當(dāng)然了也不是像Monkeyrunner那樣。
初步的想法是將各個(gè)Action進(jìn)行封裝,采用隨機(jī)調(diào)用的方式執(zhí)行測(cè)試,調(diào)用的次數(shù)可以是隨機(jī)的也可以設(shè)定,這個(gè)整體架構(gòu)的改變會(huì)對(duì)Action的錄制有相應(yīng)的要求,比如說執(zhí)行完一個(gè)Action,它的出口和入口要一致,各個(gè)Action的要在同一級(jí)別,比如在同一頁(yè)面。如此可能會(huì)出現(xiàn)多個(gè)層次,比如一個(gè)Action中又可以劃分出多個(gè)Action,這個(gè)需要采用分層的思想進(jìn)行解決,至于要分多少層,使用者可以按照自己的軟件的特點(diǎn)進(jìn)行劃分。
說的好像又些復(fù)雜了,簡(jiǎn)單的說就是按照一定的要求錄制Action,采用隨機(jī)的方式執(zhí)行Action。此方案可以檢測(cè)出不同功能之間因調(diào)用順序的不同而出現(xiàn)的BUG,實(shí)際測(cè)試也證明這種BUG是存在的,同時(shí),這種模式也使得該軟件的使用更為靈活。
暫且想法就這些,后續(xù)有再補(bǔ)上。