模塊測(cè)試單元測(cè)試
要進(jìn)行充分的單元測(cè)試,應(yīng)專門編寫測(cè)試代碼,并與產(chǎn)品代碼隔離。比較簡(jiǎn)單的辦法是為產(chǎn)品工程建立對(duì)應(yīng)的測(cè)試工程,為每個(gè)類建立對(duì)應(yīng)的測(cè)試類,為每個(gè)函數(shù)(很簡(jiǎn)單的除外)建立測(cè)試函數(shù)。
一般認(rèn)為,在結(jié)構(gòu)化程序時(shí)代,單元測(cè)試所說(shuō)的單元是指函數(shù),在當(dāng)今的面向?qū)ο髸r(shí)代,單元測(cè)試所說(shuō)的單元是指類。以類作為測(cè)試單位,復(fù)雜度高,可操作性較差,因此仍然主張以函數(shù)作為單元測(cè)試的測(cè)試單位,但可以用一個(gè)測(cè)試類來(lái)組織某個(gè)類的所有測(cè)試函數(shù)。單元測(cè)試不應(yīng)過(guò)分強(qiáng)調(diào)面向?qū)ο?,因?yàn)榫植看a依然是結(jié)構(gòu)化的。單元測(cè)試的工作量較大,簡(jiǎn)單實(shí)用高效才是硬道理。
有一種看法是,只測(cè)試類的接口(公有函數(shù)),不測(cè)試其他函數(shù),從面向?qū)ο蠼嵌葋?lái)看,確實(shí)有其道理,但是,測(cè)試的目的是找錯(cuò)并最終排錯(cuò),因此,只要是包含錯(cuò)誤的可能性較大的函數(shù)都要測(cè)試,跟函數(shù)是否私有沒有關(guān)系。對(duì)于C++來(lái)說(shuō),可以用一種簡(jiǎn)單的方法區(qū)隔需測(cè)試的函數(shù):簡(jiǎn)單的函數(shù)如數(shù)據(jù)讀寫函數(shù)的實(shí)現(xiàn)在頭文件中編寫(inline函數(shù)),所有在源文件編寫實(shí)現(xiàn)的函數(shù)都要進(jìn)行測(cè)試(構(gòu)造函數(shù)和析構(gòu)函數(shù)除外)。
我們編寫代碼時(shí),一定會(huì)反復(fù)調(diào)試保證它能夠編譯通過(guò)。如果是編譯沒有通過(guò)的代碼,沒有任何人會(huì)愿意交付給自己的老板。但代碼通過(guò)編譯,只是說(shuō)明了它的語(yǔ)法正確;我們卻無(wú)法保證它的語(yǔ)義也一定正確,沒有任何人可以輕易承諾這段代碼的行為一定是正確的。
幸運(yùn),單元測(cè)試會(huì)為我們的承諾做保證。編寫單元測(cè)試就是用來(lái)驗(yàn)證這段代碼的行為是否與我們期望的一致。有了單元測(cè)試,我們可以自信的交付自己的代碼,而沒有任何的后顧之憂。
什么時(shí)候測(cè)試?單元測(cè)試越早越好,早到什么程度?XP開發(fā)理論講究TDD,即測(cè)試驅(qū)動(dòng)開發(fā),先編寫測(cè)試代碼,再進(jìn)行開發(fā)。在實(shí)際的工作中,可以不必過(guò)分強(qiáng)調(diào)先什么后什么,重要的是高效和感覺舒適。先編寫產(chǎn)品函數(shù)的框架,然后編寫測(cè)試函數(shù),針對(duì)產(chǎn)品函數(shù)的功能編寫測(cè)試用例,然后編寫產(chǎn)品函數(shù)的代碼,每寫一個(gè)功能點(diǎn)都運(yùn)行測(cè)試,隨時(shí)補(bǔ)充測(cè)試用例。所謂先編寫產(chǎn)品函數(shù)的框架,是指先編寫函數(shù)空的實(shí)現(xiàn),有返回值的隨便返回一個(gè)值,編譯通過(guò)后再編寫測(cè)試代碼,這時(shí),函數(shù)名、參數(shù)表、返回類型都應(yīng)該確定下來(lái)了,所編寫的測(cè)試代碼以后需修改的可能性比較小。
由誰(shuí)測(cè)試?單元測(cè)試與其他測(cè)試不同,單元測(cè)試可看作是編碼??過(guò)了單元測(cè)試的代碼才是已完成的代碼,提交產(chǎn)品代碼時(shí)也要同時(shí)提交測(cè)試代碼。測(cè)試部門可以作一定程度的審核。
關(guān)于樁代碼,單元測(cè)試應(yīng)避免編寫樁代碼。樁代碼就是用來(lái)代替某些代碼的代碼,例如,產(chǎn)品函數(shù)或測(cè)試函數(shù)調(diào)用了一個(gè)未編寫的函數(shù),可以編寫樁函數(shù)來(lái)代替該被調(diào)用的函數(shù),樁代碼也用于實(shí)現(xiàn)測(cè)試隔離。采用由底向上的方式進(jìn)行開發(fā),底層的代碼先開發(fā)并先測(cè)試,可以避免編寫樁代碼,這樣做的好處有:減少了工作量;測(cè)試上層函數(shù)時(shí),也是對(duì)下層函數(shù)的間接測(cè)試;當(dāng)下層函數(shù)修改時(shí),通過(guò)回歸測(cè)試可以確認(rèn)修改是否導(dǎo)致上層函數(shù)產(chǎn)生錯(cuò)誤。
在一種傳統(tǒng)的結(jié)構(gòu)化編程語(yǔ)言中,比如C,要進(jìn)行測(cè)試的單元一般是函數(shù)或子過(guò)程。在象C++這樣的面向?qū)ο蟮恼Z(yǔ)言中, 要進(jìn)行測(cè)試的基本單元是類。對(duì)Ada語(yǔ)言來(lái)說(shuō),開發(fā)人員可以選擇是在獨(dú)立的過(guò)程和函數(shù),還是在Ada包的級(jí)別上進(jìn)行單元測(cè)試。單元測(cè)試的原則同樣被擴(kuò)展到第四代語(yǔ)言(4GL)的開發(fā)中,在這里基本單元被典型地劃分為一個(gè)菜單或顯示界面。
單元測(cè)試不僅僅是作為無(wú)錯(cuò)編碼一種輔助手段在一次性的開發(fā)過(guò)程中使用,單元測(cè)試必須是可重復(fù)的,無(wú)論是在軟件修改,或是移植到新的運(yùn)行環(huán)境的過(guò)程中。因此,所有的測(cè)試都必須在整個(gè)軟件系統(tǒng)的生命周期中進(jìn)行維護(hù)。
經(jīng)常與單元測(cè)試聯(lián)系起來(lái)的另外一些開發(fā)活動(dòng)包括代碼走讀(Code review),靜態(tài)分析(Static analysis)和動(dòng)態(tài)分析(Dynamic analysis)。靜態(tài)分析就是對(duì)軟件的源代碼進(jìn)行研讀,查找錯(cuò)誤或收集一些度量數(shù)據(jù),并不需要對(duì)代碼進(jìn)行編譯和執(zhí)行。動(dòng)態(tài)分析就是通過(guò)觀察軟件運(yùn)行時(shí)的動(dòng)作,來(lái)提供執(zhí)行跟蹤,時(shí)間分析,以及測(cè)試覆蓋度方面的信息。
一旦編碼完成,開發(fā)人員總是會(huì)迫切希望進(jìn)行軟件的集成工作,這樣他們就能夠看到實(shí)際的系統(tǒng)開始啟動(dòng)工作了。 這在外表上看來(lái)是一項(xiàng)明顯的進(jìn)步,而象單元測(cè)試這樣的活動(dòng)也許會(huì)被看作是通往這個(gè)階段點(diǎn)的道路上的障礙, 推遲了對(duì)整個(gè)系統(tǒng)進(jìn)行聯(lián)調(diào)這種真正有意思的工作啟動(dòng)的時(shí)間。
在這種開發(fā)步驟中,真實(shí)意義上的進(jìn)步被外表上的進(jìn)步取代了。系統(tǒng)能夠正常工作的可能性是很小的,更多的情況是充滿了各式各樣的Bug。在實(shí)踐中,這樣一種開發(fā)步驟常常會(huì)導(dǎo)致這樣的結(jié)果:軟件甚至無(wú)法運(yùn)行。更進(jìn)一步的結(jié)果是大量的時(shí)間將被花費(fèi)在跟蹤那些包含在獨(dú)立單元里的簡(jiǎn)單的Bug上面,在個(gè)別情況下,這些Bug也許是瑣碎和微不足道的,但是總的來(lái)說(shuō),他們會(huì)導(dǎo)致在軟件集成為一個(gè)系統(tǒng)時(shí)增加額外的工期, 而且當(dāng)這個(gè)系統(tǒng)投入使用時(shí)也無(wú)法確保它能夠可靠運(yùn)行。
在實(shí)踐工作中,進(jìn)行了完整計(jì)劃的單元測(cè)試和編寫實(shí)際的代碼所花費(fèi)的精力大致上是相同的。一旦完成了這些單元測(cè)試工作,很多Bug將被糾正,在確信他們手頭擁有穩(wěn)定可靠的部件的情況下,開發(fā)人員能夠進(jìn)行更高效的系統(tǒng)集成工作。這才是真實(shí)意義上的進(jìn)步,所以說(shuō)完整計(jì)劃下的單元測(cè)試是對(duì)時(shí)間的更高效的利用。而調(diào)試人員的不受控和散漫的工作方式只會(huì)花費(fèi)更多的時(shí)間而取得很少的好處。
使用AdaTEST和Cantata這樣的支持工具可以使單元測(cè)試更加簡(jiǎn)單和有效。但這不是必須的,單元測(cè)試即使是在沒有工具支持的情況下也是一項(xiàng)非常有意義的活動(dòng)。
它僅僅是證明這些代碼做了什么
這是那些沒有首先為每個(gè)單元編寫一個(gè)詳細(xì)的規(guī)格說(shuō)明而直接跳到編碼階段的開發(fā)人員提出的一條普遍的抱怨, 當(dāng)編碼完成以后并且面臨代碼測(cè)試任務(wù)的時(shí)候,他們就閱讀這些代碼并找出它實(shí)際上做了什么,把他們的測(cè)試工作基于已經(jīng)寫好的代碼的基礎(chǔ)上。當(dāng)然,他們無(wú)法證明任何事情。所有的這些測(cè)試工作能夠表明的事情就是編譯器工作正常。是的,他們也許能夠抓住(希望能夠)罕見的編譯器Bug,但是他們能夠做的僅僅是這些。
如果他們首先寫好一個(gè)詳細(xì)的規(guī)格說(shuō)明,測(cè)試能夠以規(guī)格說(shuō)明為基礎(chǔ)。代碼就能夠針對(duì)它的規(guī)格說(shuō)明,而不是針對(duì)自身進(jìn)行測(cè)試。這樣的測(cè)試仍然能夠抓住編譯器的Bug,同時(shí)也能找到更多的編碼錯(cuò)誤,甚至是一些規(guī)格說(shuō)明中的錯(cuò)誤。好的規(guī)格說(shuō)明可以使測(cè)試的質(zhì)量更高,所以最后的結(jié)論是高質(zhì)量的測(cè)試需要高質(zhì)量的規(guī)格說(shuō)明。
在實(shí)踐中會(huì)出現(xiàn)這樣的情況: 一個(gè)開發(fā)人員要面對(duì)測(cè)試一個(gè)單元時(shí)只給出單元的代碼而沒有規(guī)格說(shuō)明這樣吃力不討好的任務(wù)。你怎樣做才會(huì)有更多的收獲,而不僅僅是發(fā)現(xiàn)編譯器的Bug?第一步是理解這個(gè)單元原本要做什么, --- 不是它實(shí)際上做了什么。 比較有效的方法是倒推出一個(gè)概要的規(guī)格說(shuō)明。這個(gè)過(guò)程的主要輸入條件是要閱讀那些程序代碼和注釋, 主要針對(duì)這個(gè)單元, 及調(diào)用它和被它調(diào)用的相關(guān)代碼。畫出流程圖是非常有幫助的,你可以用手工或使用某種工具。 可以組織對(duì)這個(gè)概要規(guī)格說(shuō)明的走讀(Review),以確保對(duì)這個(gè)單元的說(shuō)明沒有基本的錯(cuò)誤, 有了這種最小程度的代碼深層說(shuō)明,就可以用它來(lái)設(shè)計(jì)單元測(cè)試了。
我是個(gè)很棒的程序員, 我是不是可以不進(jìn)行單元測(cè)試?
在每個(gè)開發(fā)組織中都至少有一個(gè)這樣的開發(fā)人員,他非常擅長(zhǎng)于編程,他們開發(fā)的軟件總是在第一時(shí)間就可以正常運(yùn)行,因此不需要進(jìn)行測(cè)試。你是否經(jīng)常聽到這樣的借口?
在真實(shí)世界里,每個(gè)人都會(huì)犯錯(cuò)誤。即使某個(gè)開發(fā)人員可以抱著這種態(tài)度在很少的一些簡(jiǎn)單的程序中應(yīng)付過(guò)去。 但真正的軟件系統(tǒng)是非常復(fù)雜的。真正的軟件系統(tǒng)不可以寄希望于沒有進(jìn)行廣泛的測(cè)試和Bug修改過(guò)程就可以正常工作。
編碼不是一個(gè)可以一次性通過(guò)的過(guò)程。在真實(shí)世界中,軟件產(chǎn)品必須進(jìn)行維護(hù)以對(duì)操作需求的改變作出反應(yīng), 并且要對(duì)最初的開發(fā)工作遺留下來(lái)的Bug進(jìn)行修改。你希望依靠那些原始作者進(jìn)行修改嗎? 這些制造出這些未經(jīng)測(cè)試的原始代碼的資深專家們還會(huì)繼續(xù)在其他地方制造這樣的代碼。在開發(fā)人員做出修改后進(jìn)行可重復(fù)的單元測(cè)試可以避免產(chǎn)生那些令人不快的負(fù)作用。
不管怎樣,集成測(cè)試將會(huì)抓住所有的Bug 我們已經(jīng)在前面的討論中從一個(gè)側(cè)面對(duì)這個(gè)問(wèn)題進(jìn)行了部分的闡述。這個(gè)論點(diǎn)不成立的原因在于規(guī)模越大的代碼集成意味著復(fù)雜性就越高。如果軟件的單元沒有事先進(jìn)行測(cè)試,開發(fā)人員很可能會(huì)花費(fèi)大量的時(shí)間僅僅是為了使軟件能夠運(yùn)行,而任何實(shí)際的測(cè)試方案都無(wú)法執(zhí)行。
一旦軟件可以運(yùn)行了,開發(fā)人員又要面對(duì)每個(gè)單元進(jìn)行全面的測(cè)試。 這是一件非常困難的事情,甚至在創(chuàng)造一種單元調(diào)用的測(cè)試條件的時(shí)候,要全面的考慮單元的被調(diào)用時(shí)的各種入口參數(shù)。在軟件集成階段,對(duì)單元功能全面測(cè)試的復(fù)雜程度遠(yuǎn)遠(yuǎn)的超過(guò)獨(dú)立進(jìn)行的單元測(cè)試過(guò)程。
最后的結(jié)果是測(cè)試將無(wú)法達(dá)到它所應(yīng)該有的全面性。一些缺陷將被遺漏,并且很多Bug將被忽略過(guò)去。
讓我們類比一下,假設(shè)我們要清洗一臺(tái)已經(jīng)完全裝配好的食物加工機(jī)器!無(wú)論你噴了多少水和清潔劑,一些食物的小碎片還是會(huì)粘在機(jī)器的死角位置,只有任其腐爛并等待以后再想辦法。但我們換個(gè)角度想想,如果這臺(tái)機(jī)器是拆開的, 這些死角也許就不存在或者更容易接觸到了,并且每一部分都可以毫不費(fèi)力的進(jìn)行清洗。
一個(gè)特定的開發(fā)組織或軟件應(yīng)用系統(tǒng)的測(cè)試水平取決于對(duì)那些未發(fā)現(xiàn)的Bug的潛在后果的重視程度。這種后果的嚴(yán)重程度可以從一個(gè)Bug引起的小小的不便到發(fā)生多次的死機(jī)的情況。這種后果可能常常會(huì)被軟件的開發(fā)人員所忽視(但是用戶可不會(huì)這樣),這種情況會(huì)長(zhǎng)期的損害這些向用戶提交帶有Bug的軟件的開發(fā)組織的信譽(yù),并且會(huì)導(dǎo)致對(duì)未來(lái)的市場(chǎng)產(chǎn)生負(fù)面的影響。相反地,一個(gè)可靠的軟件系統(tǒng)的良好的聲譽(yù)將有助于一個(gè)開發(fā)組織獲取未來(lái)的市場(chǎng)。
Bug發(fā)現(xiàn)的越晚,修改它所需的費(fèi)用就越高,因此從經(jīng)濟(jì)角度來(lái)看, 應(yīng)該盡可能早的查找和修改Bug。在修改費(fèi)用變的過(guò)高之前,單元測(cè)試是一個(gè)在早期抓住Bug的機(jī)會(huì)。
相比后階段的測(cè)試,單元測(cè)試的創(chuàng)建更簡(jiǎn)單,維護(hù)更容易,并且可以更方便的進(jìn)行重復(fù)。從全程的費(fèi)用來(lái)考慮, 相比起那些復(fù)雜且曠日持久的集成測(cè)試,或是不穩(wěn)定的軟件系統(tǒng)來(lái)說(shuō),單元測(cè)試所需的費(fèi)用是很低的。
這些圖表摘自<<實(shí)用軟件度量>>(Capers Jones,McGraw-Hill 1991),它列出了準(zhǔn)備測(cè)試,執(zhí)行測(cè)試,和修改缺陷所花費(fèi)的時(shí)間(以一個(gè)功能點(diǎn)為基準(zhǔn)),這些數(shù)據(jù)顯示單元測(cè)試的成本效率大約是集成測(cè)試的兩倍系統(tǒng)測(cè)試的三倍(參見條形圖)。 (術(shù)語(yǔ)域測(cè)試(Field test)意思是在軟件投入使用以后,針對(duì)某個(gè)領(lǐng)域所作的所有測(cè)試活動(dòng))
這個(gè)圖表并不表示開發(fā)人員不應(yīng)該進(jìn)行后階段的測(cè)試活動(dòng),這次測(cè)試活動(dòng)仍然是必須的。它的真正意思是盡可能早的排除盡可能多的Bug可以減少后階段測(cè)試的費(fèi)用。
其他的一些圖表顯示高達(dá)50%的維護(hù)工作量被花在那些總是會(huì)有的Bug的修改上面。如果這些Bug在開發(fā)階段被排除掉的話,這些工作量就可以節(jié)省下來(lái)。當(dāng)考慮到軟件維護(hù)費(fèi)用可能會(huì)比最初的開發(fā)費(fèi)用高出數(shù)倍的時(shí)候,這種潛在的對(duì)50%軟件維護(hù)費(fèi)用的節(jié)省將對(duì)整個(gè)軟件生命周期費(fèi)用產(chǎn)生重大的影響。
經(jīng)驗(yàn)表明一個(gè)盡責(zé)的單元測(cè)試方法將會(huì)在軟件開發(fā)的某個(gè)階段發(fā)現(xiàn)很多的Bug,并且修改它們的成本也很低。在軟件開發(fā)的后期階段,Bug的發(fā)現(xiàn)并修改將會(huì)變得更加困難,并要消耗大量的時(shí)間和開發(fā)費(fèi)用。在提供了經(jīng)過(guò)測(cè)試的單元的情況下,系統(tǒng)集成過(guò)程將會(huì)大大地簡(jiǎn)化。開發(fā)人員可以將精力集中在單元之間的交互作用和全局的功能實(shí)現(xiàn)上,而不是陷入充滿很多Bug的單元之中不能自拔。
使測(cè)試工作的效力發(fā)揮到最大化的關(guān)鍵在于選擇正確的測(cè)試策略,這其中包含了完全的單元測(cè)試的概念,以及對(duì)測(cè)試過(guò)程的良好的管理,還有適當(dāng)?shù)厥褂孟驛daTEST和Cantata這樣的工具來(lái)支持測(cè)試過(guò)程。這些活動(dòng)可以產(chǎn)生這樣的結(jié)果:在花費(fèi)更低的開發(fā)費(fèi)用的情況下得到更穩(wěn)定的軟件。更進(jìn)一步的好處是簡(jiǎn)化了維護(hù)過(guò)程并降低了生命周期的費(fèi)用。有效的單元測(cè)試是推行全局質(zhì)量文化的一部分,而這種質(zhì)量文化將會(huì)為軟件開發(fā)者帶來(lái)無(wú)限的商機(jī)。
模塊測(cè)試的目的是保證每個(gè)模塊作為一個(gè)單元能正確運(yùn)行,所以模塊測(cè)試通常又被稱為單元測(cè)試。在這個(gè)測(cè)試步驟中所發(fā)現(xiàn)的往往是編碼和詳細(xì)設(shè)計(jì)的錯(cuò)誤。
單元測(cè)試(模塊測(cè)試)是開發(fā)者編寫的一小段代碼,用于檢驗(yàn)被測(cè)代碼的一個(gè)很小的、很明確的功能是否正確。通常而言,一個(gè)單元測(cè)試是用于判斷某個(gè)特定條件(或者場(chǎng)景)下某個(gè)特定函數(shù)的行為。例如,你可能把一個(gè)很大的值放入一個(gè)有序list 中去,然后確認(rèn)該值出現(xiàn)在list 的尾部?;蛘?,你可能會(huì)從字符串中刪除匹配某種模式的字符,然后確認(rèn)字符串確實(shí)不再包含這些字符了。
單元測(cè)試(模塊測(cè)試)是由程序員自己來(lái)完成,最終受益的也是程序員自己??梢赃@么說(shuō),程序員有責(zé)任編寫功能代碼,同時(shí)也就有責(zé)任為自己的代碼編寫單元測(cè)試。執(zhí)行單元測(cè)試,就是為了證明這段代碼的行為和我們期望的一致。
工廠在組裝一臺(tái)電視機(jī)之前,會(huì)對(duì)每個(gè)元件都進(jìn)行測(cè)試,這,就是單元測(cè)試。
其實(shí)我們每天都在做單元測(cè)試。你寫了一個(gè)函數(shù),除了極簡(jiǎn)單的外,總是要執(zhí)行一下,看看功能是否正常,有時(shí)還要想辦法輸出些數(shù)據(jù),如彈出信息窗口什么的,這,也是單元測(cè)試,把這種單元測(cè)試稱為臨時(shí)單元測(cè)試。只進(jìn)行了臨時(shí)單元測(cè)試的軟件,針對(duì)代碼的測(cè)試很不完整,代碼覆蓋率要超過(guò)70%都很困難,未覆蓋的代碼可能遺留大量的細(xì)小的錯(cuò)誤,這些錯(cuò)誤還會(huì)互相影響,當(dāng)BUG暴露出來(lái)的時(shí)候難于調(diào)試,大幅度提高后期測(cè)試和維護(hù)成本,也降低了開發(fā)商的競(jìng)爭(zhēng)力。可以說(shuō),進(jìn)行充分的單元測(cè)試,是提高軟件質(zhì)量,降低開發(fā)成本的必由之路。
對(duì)于程序員來(lái)說(shuō),如果養(yǎng)成了對(duì)自己寫的代碼進(jìn)行單元測(cè)試的習(xí)慣,不但可以寫出高質(zhì)量的代碼,而且還能提高編程水平。
程序中的每一項(xiàng)功能都是測(cè)試來(lái)驗(yàn)證它的正確性。它為以后的開發(fā)提供支緩。就算是開發(fā)后期,我們也可以輕松的增加功能或更改程序結(jié)構(gòu),而不用擔(dān)心這個(gè)過(guò)程中會(huì)破壞重要的東西。而且它為代碼的重構(gòu)提供了保障。這樣,我們就可以更自由的對(duì)程序進(jìn)行改進(jìn)。
設(shè)計(jì)行為編寫單元測(cè)試將使我們從調(diào)用者觀察、思考。特別是先寫測(cè)試(test-first),迫使我們把程序設(shè)計(jì)成易于調(diào)用和可測(cè)試的,即迫使我們解除軟件中的耦合。
編寫文檔行為單元測(cè)試是一種無(wú)價(jià)的文檔,它是展示函數(shù)或類如何使用的最佳文檔。這份文檔是可編譯、可運(yùn)行的,并且它保持最新,永遠(yuǎn)與代碼同步。
具有回歸性自動(dòng)化的單元測(cè)試避免了代碼出現(xiàn)回歸,編寫完成之后,可以隨時(shí)隨地的快速運(yùn)行測(cè)試。
單元測(cè)試的范疇如果要給單元測(cè)試定義一個(gè)明確的范疇,指出哪些功能是屬于單元測(cè)試,這似乎很難。但下面討論的四個(gè)問(wèn)題,基本上可以說(shuō)明單元測(cè)試的范疇,單元測(cè)試所要做的工作。1、 它的行為和我期望的一致嗎?
這是單元測(cè)試最根本的目的,我們就是用單元測(cè)試的代碼來(lái)證明它所做的就是我們所期望的。
它的行為一直和我期望的一致嗎?編寫單元測(cè)試,如果只測(cè)試代碼的一條正確路徑,讓它正確走一遍,并不算是真正的完成。軟件開發(fā)是一個(gè)項(xiàng)復(fù)雜的工程,在測(cè)試某段代碼的行為是否和你的期望一致時(shí),你需要確認(rèn):在任何情況下,這段代碼是否都和你的期望一致;譬如參數(shù)很可疑、硬盤沒有剩余空間、緩沖區(qū)溢出、網(wǎng)絡(luò)掉線的時(shí)候。
我可以依賴單元測(cè)試嗎?不能依賴的代碼是沒有多大用處的。既然單元測(cè)試是用來(lái)保證代碼的正確性,那么單元測(cè)試也一定要值得依賴。
單元測(cè)試說(shuō)明我的意圖了嗎?單元測(cè)試能夠幫我們充分了解代碼的用法,從效果上而言,單元測(cè)試就像是能執(zhí)行的文檔,說(shuō)明了在你用各種條件調(diào)用代碼時(shí),你所能期望這段代碼完成的功能。
到這里,我們已經(jīng)列舉了使用單元測(cè)試的種種理由。也許,每個(gè)人都同意,是的,該做更多的測(cè)試。這種人人同意的事情還多著呢,是的,該多吃蔬菜,該戒煙,該多休息,該多鍛煉……這并不意味著我們中的所有人都會(huì)這么去做,不是嗎bsp; 我們知道,在開發(fā)時(shí)越早發(fā)現(xiàn)BUG,就能節(jié)省更多的時(shí)間,降低更多的風(fēng)險(xiǎn)。
下圖表摘自<<實(shí)用軟件度量>>(Capers Jones,McGraw-Hill 1991),它列出了準(zhǔn)備測(cè)試,執(zhí)行測(cè)試,和修改缺陷所花費(fèi)的時(shí)間(以一個(gè)功能點(diǎn)為基準(zhǔn)),這些數(shù)據(jù)顯示單元測(cè)試的成本效率大約是集成測(cè)試的兩倍,是系統(tǒng)測(cè)試的三倍(參見條形圖)。
術(shù)語(yǔ):域測(cè)試(Field test)意思是在軟件投入使用以后,針對(duì)某個(gè)領(lǐng)域所作的所有測(cè)試活動(dòng)。
如果你仍然認(rèn)為在編寫產(chǎn)品代碼的時(shí)候,還是沒有時(shí)間編寫測(cè)試代碼,那么請(qǐng)先考慮下面這些問(wèn)題:
1)、對(duì)于所編寫的代碼,你在調(diào)試上面花了多少時(shí)間。
2)、對(duì)于以前你自認(rèn)為正確的代碼,而實(shí)際上這些代碼卻存在重大的bug,你花了多少時(shí)間在重新確認(rèn)這些代碼上面。
3)、對(duì)于一個(gè)別人報(bào)告的bug,你花了多少時(shí)間才找出導(dǎo)致這個(gè)bug 的源碼位置。
回答完這些問(wèn)題,你一定不再以"太花時(shí)間"作為拒絕單元測(cè)試的借口。
2、 運(yùn)行測(cè)試的時(shí)間太長(zhǎng)了。
合適的測(cè)試是不會(huì)讓這種情況發(fā)生的。實(shí)際上,大多數(shù)測(cè)試的執(zhí)行都是非常快的,因此你在幾秒之內(nèi)就可以運(yùn)行成千上萬(wàn)個(gè)測(cè)試。但是有時(shí)某些測(cè)試會(huì)花費(fèi)很長(zhǎng)的時(shí)間。這時(shí),需要把這些耗時(shí)的測(cè)試和其他測(cè)試分開。通??梢悦刻爝\(yùn)行這種測(cè)試一次,或者幾天一次。
3、 測(cè)試代碼并不是我的工作。
你的工作就是保證代碼能夠正確的完成你的行為,恰恰相反,測(cè)試代碼正是你不可缺少的工作。
4、 我并不清楚代碼的行為,所以也就無(wú)從測(cè)試。
如果你實(shí)在不清楚代碼的行為,那么并不是編碼的時(shí)候。如果你并不知道代碼的行為,那么你又如何知道你編寫的代碼是正確的呢?
5、 但是這些代碼都能夠編譯通過(guò)。
我們前面已經(jīng)說(shuō)過(guò),代碼通過(guò)編譯只是驗(yàn)證它的語(yǔ)法通過(guò)。但并不能保證它的行為就一定正確。
6、 公司請(qǐng)我來(lái)是為了寫代碼,而不是寫測(cè)試。
公司付給你薪水是為了讓你編寫產(chǎn)品代碼,而單元測(cè)試大體上是一個(gè)工具,是一個(gè)和編輯器、開發(fā)環(huán)境、編譯器等處于同一位置的工具。
7、 如果我讓測(cè)試員或者QA(Quality Assurance)人員沒有工作,那么我會(huì)覺得很內(nèi)疚。
你并不需要擔(dān)心這些。請(qǐng)記住,我們?cè)诖酥皇钦務(wù)搯卧獪y(cè)試,而它只是一種針對(duì)源碼的、低層次的,為程序員而設(shè)計(jì)的測(cè)試。在整個(gè)項(xiàng)目中,還有其他的很多測(cè)試需要這些人來(lái)完成,如:功能測(cè)試、驗(yàn)收測(cè)試、性能測(cè)試、環(huán)境測(cè)試、有效性測(cè)試、正確性測(cè)試、正規(guī)分析等等。
8、 我的公司并不會(huì)讓我在真實(shí)系統(tǒng)中運(yùn)行單元測(cè)試。
我們所討論的只是針對(duì)開發(fā)者的單元測(cè)試。也就是說(shuō),如果你可以在其他的環(huán)境下(例如在正式的產(chǎn)品系統(tǒng)中)運(yùn)行這些測(cè)試的話,那么它們就不再是單元測(cè)試,而是其他類型的測(cè)試了。實(shí)際上,你可以在你的本機(jī)運(yùn)行單元測(cè)試,使用你自己的數(shù)據(jù)庫(kù),或者使用mock對(duì)象。
多數(shù)講述單元測(cè)試的文章都是以Java為例,本文以C++為例,后半部分所介紹的單元測(cè)試工具也只介紹C++單元測(cè)試工具。下面的示例代碼的開發(fā)環(huán)境是VC6.0。
產(chǎn)品類:
classCMyClass
{
public:
int Add(int i, int j);
CMyClass();
virtual ~CMyClass();
private:
int mAge; //年齡
CString mPhase; //年齡階段,如"少年","青年"
};
建立對(duì)應(yīng)的測(cè)試類CMyClassTester,為了節(jié)約編幅,只列出源文件的代碼:
void CMyClassTester::CaseBegin()
{
//pObj是CMyClassTester類的成員變量,是被測(cè)試類的對(duì)象的指針,
//為求簡(jiǎn)單,所有的測(cè)試類都可以用pObj命名被測(cè)試對(duì)象的指針。
pObj = new CMyClass();
}
void CMyClassTester::CaseEnd()
{
delete pObj;
}
測(cè)試類的函數(shù)CaseBegin()和CaseEnd()建立和銷毀被測(cè)試對(duì)象,每個(gè)測(cè)試用例的開頭都要調(diào)用CaseBegin(),結(jié)尾都要調(diào)用CaseEnd()。
接下來(lái),我們建立示例的產(chǎn)品函數(shù):
int CMyClass::Add(int i, int j)
{
return i+j;
}
和對(duì)應(yīng)的測(cè)試函數(shù):
void CMyClassTester::Add_int_int()
{
}
把參數(shù)表作為函數(shù)名的一部分,這樣當(dāng)出現(xiàn)重載的被測(cè)試函數(shù)時(shí),測(cè)試函數(shù)不會(huì)產(chǎn)生命名沖突。下面添加測(cè)試用例:
void CMyClassTester::Add_int_int()
{
//第一個(gè)測(cè)試用例
CaseBegin();{ //1
int i = 0; //2
int j = 0; //3
int ret = pObj->Add(i, j); //4
ASSERT(ret == 0); //5
}CaseEnd(); //6
}
第1和第6行建立和銷毀被測(cè)試對(duì)象,所加的{}是為了讓每個(gè)測(cè)試用例的代碼有一個(gè)獨(dú)立的域,以便多個(gè)測(cè)試用例使用相同的變量名。
第2和第3行是定義輸入數(shù)據(jù),第4行是調(diào)用被測(cè)試函數(shù),這些容易理解,不作進(jìn)一步解釋。第5行是預(yù)期輸出??錯(cuò),ASSERT是VC的斷言宏,也可以使用其他類似功能的宏,使用測(cè)試工具進(jìn)行單元測(cè)試時(shí),可以使用該工具定義的斷言宏。
示例中的格式顯得很不簡(jiǎn)潔,2、3、4、5行可以合寫為一行:ASSERT(pObj->Add(0, 0) == 0);但這種不簡(jiǎn)潔的格式卻是極力推薦的,因?yàn)樗荒苛巳唬子诮⒍鄠€(gè)測(cè)試用例,并且具有很好的適應(yīng)性,同時(shí),也是極佳的代碼文檔,總之,輸入數(shù)據(jù)和預(yù)期輸出要自成一塊。
建立了第一個(gè)測(cè)試用例后,應(yīng)編譯并運(yùn)行測(cè)試,以排除語(yǔ)法錯(cuò)誤,然后,使用拷貝/修改的辦法建立其他測(cè)試用例。由于各個(gè)測(cè)試用例之間的差別往往很小,通常只需修改一兩個(gè)數(shù)據(jù),拷貝/修改是建立多個(gè)測(cè)試用例的最快捷辦法。
下面說(shuō)說(shuō)測(cè)試用例、輸入數(shù)據(jù)及預(yù)期輸出。輸入數(shù)據(jù)是測(cè)試用例的核心,對(duì)輸入數(shù)據(jù)的定義是:被測(cè)試函數(shù)所讀取的外部數(shù)據(jù)及這些數(shù)據(jù)的初始值。外部數(shù)據(jù)是對(duì)于被測(cè)試函數(shù)來(lái)說(shuō)的,實(shí)際上就是除了局部變量以外的其他數(shù)據(jù),把這些數(shù)據(jù)分為幾類:參數(shù)、成員變量、全局變量、IO媒體。IO媒體是指文件、數(shù)據(jù)庫(kù)或其他儲(chǔ)存或傳輸數(shù)據(jù)的媒體,例如,被測(cè)試函數(shù)要從文件或數(shù)據(jù)庫(kù)讀取數(shù)據(jù),那么,文件或數(shù)據(jù)庫(kù)中的原始數(shù)據(jù)也屬于輸入數(shù)據(jù)。一個(gè)函數(shù)無(wú)論多復(fù)雜,都無(wú)非是對(duì)這幾類數(shù)據(jù)的讀取、計(jì)算和寫入。預(yù)期輸出是指:返回值及被測(cè)試函數(shù)所寫入的外部數(shù)據(jù)的結(jié)果值。返回值就不用說(shuō)了,被測(cè)試函數(shù)進(jìn)行了寫操作的參數(shù)(輸出參數(shù))、成員變量、全局變量、IO媒體,它們的預(yù)期的結(jié)果值都是預(yù)期輸出。一個(gè)測(cè)試用例,就是設(shè)定輸入數(shù)據(jù),運(yùn)行被測(cè)試函數(shù),然后判斷實(shí)際輸出是否符合預(yù)期。下面舉一個(gè)與成員變量有關(guān)的例子:
void CMyClass::Grow(int years)
{
mAge += years; if(mAge < 10)
mPhase = "兒童";
else if(mAge <20)
mPhase = "少年";
else if(mAge <45)
mPhase = "青年";
else if(mAge <60)
mPhase = "中年";
else
mPhase = "老年";
}
測(cè)試函數(shù)中的一個(gè)測(cè)試用例:
CaseBegin();{
int years = 1;
pObj->mAge = 8;
pObj->Grow(years);
ASSERT( pObj->mAge == 9 );
ASSERT( pObj->mPhase == "兒童" );
}CaseEnd();
在輸入數(shù)據(jù)中對(duì)被測(cè)試類的成員變量mAge進(jìn)行賦值,在預(yù)期輸出中斷言成員變量的值??梢钥吹酵扑]的格式的好處了吧,這種格式可以適應(yīng)很復(fù)雜的測(cè)試。在輸入數(shù)據(jù)部分還可以調(diào)用其他成員函數(shù),例如:執(zhí)行被測(cè)試函數(shù)前可能需要讀取文件中的數(shù)據(jù)保存到成員變量,或需要連接數(shù)據(jù)庫(kù),把這些操作稱為初始化操作。例如,上例中 ASSERT( ...)之前可以加pObj->OpenFile();。為了訪問(wèn)私有成員,可以將測(cè)試類定義為產(chǎn)品類的友元類。例如,定義一個(gè)宏:
#define UNIT_TEST(cls) friend class cls##Tester;
然后在產(chǎn)品類聲明中加一行代碼:UNIT_TEST(ClassName)。
下面談?wù)劀y(cè)試用例設(shè)計(jì)。前面已經(jīng)說(shuō)了,測(cè)試用例的核心是輸入數(shù)據(jù)。預(yù)期輸出是依據(jù)輸入數(shù)據(jù)和程序功能來(lái)確定的,也就是說(shuō),對(duì)于某一程序,輸入數(shù)據(jù)確定了,預(yù)期輸出也就可以確定了,至于生成/銷毀被測(cè)試對(duì)象和運(yùn)行測(cè)試的語(yǔ)句,是所有測(cè)試用例都大同小異的,因此,我們討論測(cè)試用例時(shí),只討論輸入數(shù)據(jù)。
前面說(shuō)過(guò),輸入數(shù)據(jù)包括四類:參數(shù)、成員變量、全局變量、IO媒體,這四類數(shù)據(jù)中,只要所測(cè)試的程序需要執(zhí)行讀操作的,就要設(shè)定其初始值,其中,前兩類比較常用,后兩類較少用。顯然,把輸入數(shù)據(jù)的所有可能取值都進(jìn)行測(cè)試,是不可能也是無(wú)意義的,我們應(yīng)該用一定的規(guī)則選擇有代表性的數(shù)據(jù)作為輸入數(shù)據(jù),主要有三種:正常輸入,邊界輸入,非法輸入,每種輸入還可以分類,也就是平常說(shuō)的等價(jià)類法,每類取一個(gè)數(shù)據(jù)作為輸入數(shù)據(jù),如果測(cè)試通過(guò),可以肯定同類的其他輸入也是可以通過(guò)的。下面舉例說(shuō)明:
正常輸入
例如字符串的Trim函數(shù),功能是將字符串前后的空格去除,那么正常的輸入可以有四類:前面有空格;后面有空格;前后均有空格;前后均無(wú)空格。
邊界輸入
上例中空字符串可以看作是邊界輸入。
再如一個(gè)表示年齡的參數(shù),它的有效范圍是0-100,那么邊界輸入有兩個(gè):0和100。
非法輸入
非法輸入是正常取值范圍以外的數(shù)據(jù),或使代碼不能完成正常功能的輸入,如上例中表示年齡的參數(shù),小于0或大于100都是非法輸入,再如一個(gè)進(jìn)行文件操作的函數(shù),非法輸入有這么幾類:文件不存在;目錄不存在;文件正在被其他程序打開;權(quán)限錯(cuò)誤。
如果函數(shù)使用了外部數(shù)據(jù),則正常輸入是肯定會(huì)有的,而邊界輸入和非法輸入不是所有函數(shù)都有。一般情況下,即使沒有設(shè)計(jì)文檔,考慮以上三種輸入也可以找出函數(shù)的基本功能點(diǎn)。實(shí)際上,單元測(cè)試與代碼編寫是"一體兩面"的關(guān)系,編碼時(shí)對(duì)上述三種輸入都是必須考慮的,否則代碼的健壯性就會(huì)成問(wèn)題。
上面所說(shuō)的測(cè)試數(shù)據(jù)都是針對(duì)程序的功能來(lái)設(shè)計(jì)的,就是所謂的黑盒測(cè)試。單元測(cè)試還需要從另一個(gè)角度來(lái)設(shè)計(jì)測(cè)試數(shù)據(jù),即針對(duì)程序的邏輯結(jié)構(gòu)來(lái)設(shè)計(jì)測(cè)試用例,就是所謂的白盒測(cè)試。如果黑盒測(cè)試是足夠充分的,那么白盒測(cè)試就沒有必要,可惜"足夠充分"只是一種理想狀態(tài),例如:真的是所有功能點(diǎn)都測(cè)試了嗎?程序的功能點(diǎn)是人為的定義,常常是不全面的;各個(gè)輸入數(shù)據(jù)之間,有些組合可能會(huì)產(chǎn)生問(wèn)題,怎樣保證這些組合都經(jīng)過(guò)了測(cè)試?難于衡量測(cè)試的完整性是黑盒測(cè)試的主要缺陷,而白盒測(cè)試恰恰具有易于衡量測(cè)試完整性的優(yōu)點(diǎn),兩者之間具有極好的互補(bǔ)性,例如:完成功能測(cè)試后統(tǒng)計(jì)語(yǔ)句覆蓋率,如果語(yǔ)句覆蓋未完成,很可能是未覆蓋的語(yǔ)句所對(duì)應(yīng)的功能點(diǎn)未測(cè)試。
白盒測(cè)試針對(duì)程序的邏輯結(jié)構(gòu)設(shè)計(jì)測(cè)試用例,用邏輯覆蓋率來(lái)衡量測(cè)試的完整性。邏輯單位主要有:語(yǔ)句、分支、條件、條件值、條件值組合,路徑。語(yǔ)句覆蓋就是覆蓋所有的語(yǔ)句,其他類推。另外還有一種判定條件覆蓋,其實(shí)是分支覆蓋與條件覆蓋的組合,在此不作討論。跟條件有關(guān)的覆蓋就有三種,解釋一下:條件覆蓋是指覆蓋所有的條件表達(dá)式,即所有的條件表達(dá)式都至少計(jì)算一次,不考慮計(jì)算結(jié)果;條件值覆蓋是指覆蓋條件的所有可能取值,即每個(gè)條件的取真值和取假值都要至少計(jì)算一次;條件值組合覆蓋是指覆蓋所有條件取值的所有可能組合。做過(guò)一些粗淺的研究,發(fā)現(xiàn)與條件直接有關(guān)的錯(cuò)誤主要是邏輯操作符錯(cuò)誤,例如:||寫成&&,漏了寫!什么的,采用分支覆蓋與條件覆蓋的組合,基本上可以發(fā)現(xiàn)這些錯(cuò)誤,另一方面,條件值覆蓋與條件值組合覆蓋往往需要大量的測(cè)試用例,因此,條件值覆蓋和條件值組合覆蓋的效費(fèi)比偏低。效費(fèi)比較高且完整性也足夠的測(cè)試要求是這樣的:完成功能測(cè)試,完成語(yǔ)句覆蓋、條件覆蓋、分支覆蓋、路徑覆蓋。做過(guò)單元測(cè)試的朋友恐怕會(huì)對(duì)測(cè)試要求給予一個(gè)字的評(píng)價(jià):暈!因?yàn)檫@似乎是不可能的要求,要達(dá)到這種測(cè)試完整性?所以提出這種測(cè)試要求,是因?yàn)槔靡恍┕ぞ?,可以在較低的成本下達(dá)到這種測(cè)試要求,后面將會(huì)作進(jìn)一步介紹。
關(guān)于白盒測(cè)試用例的設(shè)計(jì),程序測(cè)試領(lǐng)域的書籍一般都有講述,普通方法是畫出程序的邏輯結(jié)構(gòu)圖如程序流程圖或控制流圖,根據(jù)邏輯結(jié)構(gòu)圖設(shè)計(jì)測(cè)試用例,這些是純粹的白盒測(cè)試,所推薦的方法是:先完成黑盒測(cè)試,然后統(tǒng)計(jì)白盒覆蓋率,針對(duì)未覆蓋的邏輯單位設(shè)計(jì)測(cè)試用例覆蓋它,例如,先檢查是否有語(yǔ)句未覆蓋,有的話設(shè)計(jì)測(cè)試用例覆蓋它,然后用同樣方法完成條件覆蓋、分支覆蓋和路徑覆蓋,這樣的話,既檢驗(yàn)了黑盒測(cè)試的完整性,又避免了重復(fù)的工作,用較少的時(shí)間成本達(dá)到非常高的測(cè)試完整性。不過(guò),這些工作可不是手工能完成的,必須借助于工具,后面會(huì)介紹可以完成這些工作的測(cè)試工具。
現(xiàn)在開始介紹單元測(cè)試工具,都是用于C++語(yǔ)言的。
首先是CppUnit,這是C++單元測(cè)試工具的鼻祖,免費(fèi)的開源的單元測(cè)試框架。由于已有一眾高人寫了不少關(guān)于CppUnit的很好的文章,想了解CppUnit的朋友,建議讀一下Cpluser 所作的《CppUnit測(cè)試框架入門》,該文也提供了CppUnit的下載地址。
然后介紹C++Test,這是Parasoft公司的產(chǎn)品。[C++Test是一個(gè)功能強(qiáng)大的自動(dòng)化C/C++單元級(jí)測(cè)試工具,可以自動(dòng)測(cè)試任何C/C++函數(shù)、類,自動(dòng)生成測(cè)試用例、測(cè)試驅(qū)動(dòng)函數(shù)或樁函數(shù),在自動(dòng)化的環(huán)境下極其容易快速的將單元級(jí)的測(cè)試覆蓋率達(dá)到100%]。[]內(nèi)的文字引自,這是華唐公司的網(wǎng)頁(yè)。想要購(gòu)買或索取報(bào)價(jià)、試用版,建議訪問(wèn)該公司的網(wǎng)站。
最后介紹Visual Unit,簡(jiǎn)稱VU,這是國(guó)產(chǎn)的單元測(cè)試工具,據(jù)說(shuō)申請(qǐng)了多項(xiàng)專利,擁有一批創(chuàng)新的技術(shù)。[自動(dòng)生成測(cè)試代碼 快速建立功能測(cè)試用例程序行為一目了然 極高的測(cè)試完整性 高效完成白盒覆蓋 快速排錯(cuò) 高效調(diào)試 詳盡的測(cè)試報(bào)告]。[]內(nèi)的文字是VU開發(fā)商的網(wǎng)頁(yè)上摘錄的。前面所述測(cè)試要求:完成功能測(cè)試,完成語(yǔ)句覆蓋、條件覆蓋、分支覆蓋、路徑覆蓋,用VU可以輕松實(shí)現(xiàn),還有一點(diǎn)值得一提:使用VU還能提高編碼的效率,總體來(lái)說(shuō),在完成單元測(cè)試的同時(shí),編碼調(diào)試的時(shí)間還能大幅度縮短。介紹工具索然無(wú)味,畢竟工具好不好用,合不合用,要試過(guò)才知道,還是自己去開發(fā)商的網(wǎng)站看吧,可以下載演示版,還有演示課件。
關(guān)閉其它電腦,只打開1臺(tái)電腦,作下載測(cè)試,下載資源多的東西,你4M的,下載速度最大512k/s,接近或比這速度稍大就是正常的了,還有看看你的其它電腦,是不是有人在下載或者使用BT,等網(wǎng)絡(luò)占用比較大的軟...
測(cè)試完畢
收到
格式:pdf
大?。?span id="pnq9keq" class="single-tag-height">49KB
頁(yè)數(shù): 5頁(yè)
評(píng)分: 4.5
單元測(cè)試 4 一、單項(xiàng)選擇題 1、 《熱網(wǎng)規(guī)范》規(guī)定,輸送干線每隔( )米需裝設(shè)一個(gè)分段閥門。 A. 1000-2000 B. 2000-3000 C. 3000-4000 D. 4000-5000 2、 對(duì)熱水供熱系統(tǒng)起定壓作用的設(shè)備,稱為( )。
格式:pdf
大?。?span id="rvmyscf" class="single-tag-height">49KB
頁(yè)數(shù): 2頁(yè)
評(píng)分: 4.5
簡(jiǎn) 單 機(jī) 械 單 元 測(cè) 試 題
一、選擇題(共 8 小題 . 每題 3 分,共 2 4 分)
1、以下關(guān)于杠桿的說(shuō)法正確的是
A、杠桿是能繞支點(diǎn)轉(zhuǎn)動(dòng)的彈性棒 B 、天平是利用杠桿的平衡條件來(lái)稱出物體的質(zhì)量的
C、使用杠桿的目的是為了省力 D 商販不慎在稱砣上沾了一塊泥,他賣給顧客的菜將會(huì)缺斤少兩
2、如圖所示,將物體 G分別沿斜面 AC和 BC推到頂端 C,所用的力分別是 F1和 F2,
所做的功分別是 W1和 W2,不計(jì)摩擦,比較它們的大?。?A、 F1>F2 W1=W2 B、 F1
本標(biāo)準(zhǔn)規(guī)定了由硅基絕緣柵雙極晶體管(IGBT)以及碳化硅肖特基二極管構(gòu)成的混合功率半導(dǎo)體模塊的術(shù)語(yǔ)、文字符號(hào)、基本額定值和特性以及測(cè)試方法等產(chǎn)品特性要求。
張瑾,仇志杰,陸敏,彭同華,劉振洲,王志超,陳彤,鄭紅軍, 林雪如,陳鵬,劉祎晨