三問TDD 單元測試總是好的嗎?

2021-09-05 18:39:07 字數 3939 閱讀 7319

原帖:

再問tdd: 擴散角模型

有關測試「後行」也可以接受的說法,說明了乙個事實:即使是最中堅的測試粉絲,也經常需要修正自我。很多理論丟擲來之後,在現實面前,都不斷的妥協。一些妥協到基本完善,一些妥協到基本完蛋。

說實話,我表面上是乙個保守派,其實骨子裡是個激進派。幾年前我的想法深度和廣度都不足,實際上也非常容易跟潮流; 現在情況稍微好了一點(我只敢這麼說),所以我的激進反而表現在,無論你多牛的人提出,再多的人捧場,只要讓我覺得不舒服,同時這種不舒服是存在道理支撐的,我就會比倡導者更早的進入砍掉多餘內容或增加判定條件的過程。 如果我說我對流行趨勢不屑一顧,那我太張狂了,也不是實情。實際情況是,我關注它們能帶來的東西,但也確實持謹慎態度,同時或多或少的能感覺到一點它們必將發生的修正道路。

關於先行還是後行(雖然後行已然很難說是tdd,同時失去了先行測試的一些重要優勢),其實我在乎的不是這個。存在很多情況,後行會比較舒服,這是必然的。但是關於「必須」這個詞,我覺得還是太絕對了。我們都不必考慮單元測試對靜態語言到底發揮多大作用,也不必去注意單元測試的最大受益者是動態語言這一事實,只要再考慮一下我說的「擴散角」模型就夠了。

在很多情況下,乙個隱含bug但能以95%的概率正確完成任務的東西,比因為抱有單元測試在各個粒度級別必須達到一定覆蓋的想法,而超過了成本能承擔的極限所造成的問題,還是要好得多。 反過來,另一些情況下,乙個隱含著定時炸彈的程式是相當危險的,比如醫療方面的嵌入式軟體。 雖然軟體和參與人員的規模本身就會對流程和組織結構的進行產生重大影響,但是如上所述的基本道理,仍然是在何種程度上確立測試的標準和規模的重要因素。

如果讓我倡導測試理念,我覺得除了掌握好測試的切入點和目標的粒度,乙個首先要學會的東西,就是在列表裡劃出優先順序,同時標出不可獲缺的測試,和那些如果砍掉對置信度影響極其輕微的測試。 另外一方面,排除那些「先行測試」的重大優勢,具體到可以「後行」的單元測試,我認為單元測試的必要性,很多時候來自於開發者腦中對該單元的不確定性。有些時候,直接抹掉不確定性的成本要高於使用測試的成本,這時候測試就是必要的;而再另一些時候,測試不過是對腦海中確定的東西換一種方式重複一遍罷了。

後者本身是不需要什麼單元測試的,但是很多人總在強調一件事:是人就會犯錯。但這種說法沒有考慮該事實的另外乙個方面:既然是人就會犯錯,當你重複自己的時候,或別人重複相同的知識的時候,也仍然存在犯錯的機率。這個事實所帶來的結果可能是非常讓人驚詫的:當我們無差別的認為所有目標都應該進行單元測試時,有可能使得結果的置信度被降低; 最終要麼造成更大的麻煩,要麼反而使得軟體的可靠性受到影響。這或許有點聳人聽聞,但這就是我為什麼強調,增加乙個環節,有時候並不只是增加工作量,而是引入更多的混亂的其中乙個可能的原因。

所以在這裡,我可以很個人的給單元測試增加乙個「必要性指標」,這個指標是由測試目標可能存在的不確定性所決定的。對於較大型的組織來說,應該對這事有乙個統一的判斷標準,哪怕僅僅是測試目標的預期的**行數; 更好的做法是對複雜度建立起統一且規範的判定標準。這樣做甚至對於那些肯定應該進行的測試,也能起到一定的輔助作用(比如認識上的)。

好鋼要使在刀刃上。說到底,無論是測試,還是硬生生的除錯,我們關心的不是別的,還是成本的問題: 哪怕一團糟,我們如果有無限的時間,無限的金錢,愛怎麼寫根本無所謂。所以當我們說測試是「必須」的時候,或者說測試毫無用處的時候,最好還是先看看表,數數人頭,再摸摸自己的錢包; 也許他們會讓你不得不選擇去寫某些測試,但是對另一些情況和其它一些測試,答案正好相反。另外,如果對負面效果無法做出清晰的認識,我們可以去用,但不要對測試產生依賴性。

總而言之,很多測試倡導者的問題,恰恰不是過於重視測試,而是對待測試的態度過於輕易了。我們無論使用什麼手段,實質上追求的僅僅是乙個概率,這數字到底是會上公升還是下降,是乙個問題; 提高每乙個百分比所要付出的代價,也還是要精打細算才成。 對每乙個可能帶來變化的決定,只有四個字: 如臨大敵,如履薄冰。

另外,我希望大家注意乙個倡導了20年的,比測試要輕量的多,甚至更應該作為一種良好習慣的程式設計技巧,既子程式(routine)內的斷言。乙個測試如果「後行」是可以被允許的,那麼也許這個測試可以部分的用斷言代替:當斷言認證了所有造成不確定的點,我們就沒必要在測試中重複這些知識,從而避免引入新的不確定性。 凡是適合使用斷言增加置信度的地方,我個人的看法是,斷言的價效比相對測試要高得多;唯一需要注意的是,斷言在某些場景下也會連帶一些負面的效果,或者成本比測試還要高; 這仍然是對不同手段適用性的判斷。更多的思考是,在稍微大一些的組織內,我們無法確認程式設計師是不是正確的在子程式內使用了斷言。但在這上面,我覺得,信任程式設計師比信任測試員好: 對相同的知識,前者有乙個產生風險的主體,後者卻有兩個。

說實話,我覺得有些大牛和他們的文章都有點,怎麼說呢? 不夠嚴肅,或者說不夠嚴謹。 實際上建立簡單的模型和進行基本的分析,對一些要素的覆蓋達到一定比例,就可以獲得更好的指導原則;但是我要說的是,他們在宣傳時忽略了這些工作,或者說對這些方面沒有很好的展開;更沒有盡職盡責的把這些表面之下的工作結果,推廣到受眾群裡去。一些人可能是沒時間,也沒這個義務;但另一些人,就像我說ms隱藏asp.net的複雜性一樣,是故意的。

我覺得這才是我這類譁眾取寵之人存在的最大的必要性:做乙個提醒。但是我這類人也絕不可能花幾個月時間,進行分析研究工作,然後拿出乙個嚴謹的,令人信服的行動的初步指南。這些工作還是必須大家自己去做,尤其是某一理念的追隨者們需要付出更多。

最後說明,如果場景要求或者規定非測試不可,我更多的傾向於「先行測試」;主要是因為「先行測試」不僅僅帶來提高置信度的好處: 在很多情況下,這些額外的東西才是tdd的理念或者比如使用測試的方法如敏捷所關心的首要問題。另外,我不太想**測試或具體某種測試的必要性;我真正想強調的是,我們需要更多的擁有足夠判斷力的人,才可以做出更多的正確的決定,讓從行業到具體組織內部的軟體構件水平,上公升乙個台階。

update:

附錄: 取自

venus神廟的

小扯一下除錯。。。

後半段。紅色為怪怪的注釋。

到偵錯程式,不得不說測試(這裡指的是程式設計師個人的單元測試...)。在此前一點概念需要說明。在很多人概念裡,除錯簡單的對應使用偵錯程式,與測試是格格 不入的。而在本書中,除錯,指為了發現錯誤的起因所使用的所有手段,其中包含測試。測試最最最最優良的一點在於它是自動化的(這是個要點)。或者說是可永遠重現的(這是付出好幾方面的代價交換來的,因為測試也是人手工編寫的)。這就 是說,使用測試,可以幫你解決誘發錯誤,重現錯誤等及其麻煩的事情。但是,測試往往只是能夠幫你找到錯誤的出現點,而不總是能快速的把你帶到錯誤的起因 點,而為了部署這些測試你需要花費很多的精力。正是基於此,包括雲風老大

(此人真是讓人又愛又恨...,從這方面來說和linus有點像)等很多人不屑使用測試(再次強調,這是指個人的單元測試...)。但是,這部以為這測試不重要,而成為你可以肆意偷懶放低**質量的藉口。而是因為其帶來的好處被其他的一些技術抵消了(也可以被非技術因素抵消),這樣的話,為其付出的代價就會顯得很沉重。

但是無論你使用什麼樣的手段進行除錯。**結構的質量才是最最最根本的內容。乙個函式劃分很細緻,不大量濫用全域性變數的**,使用很多無***的函式,通 過測試你發現錯誤出現點,往往你就能很快到達錯誤起點(因為你把錯誤可能出現的地方限定在了有限的範圍)。而如果你**結構混沌不堪,函式/類之間關係錯 綜複雜,哪怕你用測試找到了錯誤出現點,開著偵錯程式進去看,你也會很快轉暈。所以提高**質量,合理應用適合的除錯工具和手段,正確使用除錯的方法才是正 道。在這裡,不得不提一下tdd。最初的時候我總覺得tdd最核心的是t,test。後來才開始明白,它最核心的其實是d,drive(我非常認同,這就是我說的測試之外的東西)。你可以把測試寫的 很弱,但你一定要在此影響下把**重構的很好。由此得到乙個蠻歪的理:如果你或你團隊的**素質很高,可以嘗試不用tdd的一些開發手段(不認同簡單的以人的水平決定,而是如我正文所說,按照一定的條件作出判斷);但如果你或你團 隊**素質不夠高,請把自己套在tdd裡面磨練一下。之所以說歪,是因為我其實只想說後半句,前半句純屬為了對仗工整而用。

最後我發現我忘提乙個很好玩的東西,斷言。我一直覺得這個東西很有意思。是一種游離在單元測試與偵錯程式之外的手段,是乙個隱藏在事後分析中的事前推測派來 的間諜。assert的意義在於猜測並提醒一些最有可能的錯誤,它不精確但也不死板。我一直覺得,全面合理的鋪下斷言這張網(三個部分,輸入輸出不變 式),可以很有效的提高除錯速度。

(呵呵,對這段沒啥可說的,支援)

單元測試(三) 建立多執行緒單元測試

junit本是不支援多執行緒的,乙個單元測試case主程序跑完,其他new出來的執行緒都會gg思密達。此篇mark乙份在junit中執行多執行緒的方法。net.sourceforge.groboutils groboutils core 5test slf4j public class device...

單元測試之路(三)

自動生成測試集,unittest.makesuite unittest.makesuite testcaseclass,prefix test 兩個引數,測試用例的類以及規定測試用例以 test 開頭 1.將乙個測試類下的testcase自動識別為測試用例 import unittest from ...

單元測試 單元測試編寫的原則

公司要求提公升單元測試的質量,其中我作為方案和推動的主導,對開發過程中的單元測試,有了一些思考和總結 單元測試編寫的目的,是面向計算機特性的,基於函式的in out,所以單元測試的好幫手就是斷言,通過不斷的構造輸出並對結果進行斷言,我們就可以針對乙個物件以及它的函式,構建出充足的用例去包裹它,以期望...