文章出處

這篇博客,我把他從《架構之路》移到了《項目管理》。之前把它放到《架構之路》,因為它其實是受到了測試驅動的啟發或影響;但文章完成之后,不光我自己,就連讀者,都覺得這顯然應屬于項目管理的范疇。

 

需求文檔可測試化

我第一點想到的,就是需求文檔應該可測試化。我不太明白,這樣簡單有效的一個工作,為什么幾乎沒有人去做?因為發包方的原因?

大家接觸到的需求文檔是什么樣子的?我從來沒有看到過一份我滿意的需求文檔。都是word格式的,文字加上圖片說明。文字都是簡單的陳述句說明,比如:用戶名不能重復。簡明扼要,是不是?是你媽個逼!sorry,我爆粗口了,但這種文檔真的會讓你瘋掉的!

 

你覺得這是一個很簡單的需求,是吧?然后你就噼里啪啦的開始編碼了,20分鐘搞定,躊躇滿志,小case啊!

然后噩夢就開始了。

第一次驗收。發包方的眉毛皺了起來,“嗯,其實我想的是那種:當用戶把用戶名輸入完成之后,能立即顯示該用戶名是否重復,而不用點擊提交之后才顯示這個結果,你看XXXX網站就是這樣的”OK,Ajax效果是吧?好呢,我改。感謝asp.net mvc,有現成的Remote實現,20分鐘,收工,over!

第二次驗收。發包方有點不耐煩了,“你這個還是不對啊!你看我給你說了XXXX網站,如果這個用戶名不重復的話,要打個勾啊;錯了,打個叉,再顯示‘用戶名重復’的提示啊……”。你有沒有想哭的感覺?我忍,含著淚,找個勾勾叉叉的圖片,再改。

第三次驗收。發包方終于笑了,“不錯不錯!”你心里一塊石頭落了地。但這發包方思維很嚴密,他突然想到一個問題,“你說,假如兩個用戶同時注冊,用的是同樣的用戶名,這個用戶名也是以前數據庫里沒有的。所以頁面輸入的時候,肯定是顯示用戶名有效,是吧?所以他們都可以提交,但他們用戶名又是一樣的,都提交了就重復了,這時候會發生什么情況?……”你仔細的想了想,是不是覺得晴天霹靂天旋地轉?

這只是一個非常非常簡單普通的需求,都可以演化出無數種具體實現,更何況其他你可能從來沒接觸過的復雜需求?你作為一個程序員,只是覺得苦逼郁悶或者還得趕工加班;但對于公司來說,這就是個大麻煩了:工期延誤、費用增加、信譽破產……這時候該追究誰的責任?我們可以設想這樣的對話:

 

發包方向你們公司老大抱怨:“張總,你們這個項目都延期好幾次了,我不好交代了呀!”

公司老大張總叫來項目經理:“這個項目怎么回事?趕快去催一下。”

項目經理找到你:“怎么一個功能做這么久?你是怎么搞的?”

你:“我怎么搞的?需求改了N遍了!我還想問你是怎么定的需求呢?你看……”

項目經理找到公司老大:“張總,這個客戶的需求變了啊!一直改需求,我們……”

公司老大找到發包方:“這個劉總,這個項目你們改了需求啊!不光這個工期不行,費用也得考慮考慮啊,呵呵!”

發包方就炸了,“還要加錢?你們這些個奸商!合同不是寫得好好的,一口價……”

“不是改了需求么?”

“我哪里改?就不過‘用戶名不能重復’啊,我改成了‘用戶名可以重復’?”

“不是。我們最開始以為……,結果……”

“你們為什么最開始不提出來呢?你們是專業人士,你們應該把這些問題考慮到的呀!還虧得我們思慮周全,我們業余人員都能想到的,你們怎么就想不到呢?你們怎么樣的一個業務素質?……”

(程序員同學,說句題外話,老板在外面受的氣不是你們所能想象的。你以為他們在外面吃喝玩樂好不瀟灑,他們實際上就一個“三陪”而已,陪吃陪喝陪笑,不比做小姐的好到哪里去!都是給你們“背黑鍋”“揩屁股”啊。)

 

就事論事,這件事的責任還真賴不到發包方。他的需求最多算是“不明確”,你不能說他“變更”了需求。但是,不明確的需求你接受了,責任就轉移到你的身上了。退一萬步講,你是“專業人士”,你真的應該考慮得比發包方周全。

所以,你觀察周圍經驗老到的程序員,他們拿到這個需求是不會立馬動手敲代碼的。他們一定會想一想,多問幾個具體細節,覺得沒有問題之后,才開始動手。所以他返工就少,他就是可以不加班,這就是人家的本事。

 

但是,正如我反復強調的,架構/管理的目的,應該是通過一種制度一種流程來避免上述問題,而不是靠個人技巧經驗。追根溯源,解決這個問題,就應該“明確需求”——也就是說,需求不能這樣懵懵懂懂大而化之,必須相當的明確清晰,具有唯一性。怎么實現?需求文檔可測試化。或者你可以理解為:把需求文檔像測試文檔一樣寫。比如,上述需求就變成:

  • 在注冊頁面
  1. 輸入用戶名xxxx,移出焦點,頁面不刷新,顯示圖標“叉”和錯誤提示:用戶名重復
  2. 輸入用戶名yyyy,移出焦點,頁面不刷新,顯示圖標“勾”
  3. ……

這份需求/測試文檔,交發包方審核確認;之后驗收,就嚴格按該文檔逐項進行,所有測試通過,驗收合格。如果需要加需求,一般都得加測試;加測試,那不用說,我們就來談談時間費用的問題。

 

BuildDatabase

在一些文檔規范嚴格的公司,實際上是同時有一份開發文檔和測試文檔的。但開發人員在整個開發過程中,并沒有參考測試文檔,所以最后就很容易造成測試階段開發人員不斷地返工,開發人員和測試人員之間矛盾尖銳。但最終80%的情況,還是開發的問題,畢竟你是做事的人,人家是檢查的人。所以為什么不從一開始,就把需求文檔、測試文檔和開發文檔合其為一呢?(當然,分開寫,會有一些“監督”的作用,但我始終覺得,這種監督效率不高,投入產出不劃算)

 

而且我發現,這些測試文檔,都有一個問題:操作繁瑣不經濟。

仍以“用戶名不能重復”為例,我看到的測試文檔大致就是這樣寫的:

  1. 以test-1112為用戶名注冊一個新用戶
  2. 再使用test-1112為用戶名進行注冊
  3. 頁面顯示錯誤提示:用戶名重復
  4. ……

表面上看起來沒有問題,但是如果測試次數多了的話,就會感覺每次先去注冊一個新用戶很麻煩。而且,這只是最簡單的功能,如果功能復雜,要求準備的數據多/難/特殊,怎么辦?我們又講一個故事吧。

 

項目上線前夕,測試人手不夠,我們開發過去幫忙。我跑一個test case,跑了一個多星期!你信不信?我的問題就在于測試的這個數據做不出來。測試文檔是一步步寫清楚了的,但你這樣做不下去:權限不夠、數據已有變化、文檔模糊……到處找人問。找到懂這事的人,中途又發現,程序(頁面)發生了更改,有些功能跑不起來……最后一個workaround,得改數據庫,數據庫又得找DBA啊……總之,這個test case搞得雞飛狗跳,好在最后還是跑出來了——但以后(下一次)怎么辦, 我就不知道了。

 

本質上,這種做法,測試數據是要測試人員自己“做”,或者“找”的,有很多問題。所以,從那時開始,我就在想:能不能把測試用的數據“固化”下來?讓測試人員就基本上不用“做”,或者很方便的就能“找”打測試數據。比如:“用戶名不能重復”的文檔就直接寫成:

  1. 使用test-1112為用戶名進行注冊
  2. 頁面顯示錯誤提示:用戶名重復

最多加一個說明:test-1112是已有用戶名,用戶名不能重復。

 

這個誘惑一直吸引著我,最后我在solution中就引入了一個BuildDatatase項目,專門為開發測試準備數據。毫無疑問,這個決定也遭到了開發人員的抵制。因為這個數據也不是那么好做的,具體我們將在項目詳解里談。

我鐵腕推行,大概經過了兩件事,他們慢慢的就習慣/認同了這種做法。

 

第一件事,是任務列表頁面。開發代碼之前是寫好了的,而且已經跑了一段時間了。我讓他為該頁面重新創建測試數據,他一臉不可置信:這種篩選排序,天?要準備多少數據?!怎么準備?代碼都寫好了,跑得好好的,有必要嗎?

我讓他先冷靜一下。然后有以下對話:

“如果你不準備這些數據,你怎么保證你代碼的正確性?”我問。

“就直接在頁面上建幾個任務啊,然后跑一下。”他想了想。

“要建幾個呢?”我繼續追問。

“……”,他一時答不出來。

“隨便做幾個數據,隨便的跑一跑,然后就不管了,是吧?你以前就是這樣做的?”,我接著說,“所以我們的代碼沒有質量。然后如果沒有專門的測試呢,就讓用戶當免費測試員;有測試呢,我們就把這些臟活累活扔給他們。他們一遍遍的報bug跑不過,我們還不服氣還有怨氣……為什么我們不一開始就把它做好呢?”

首先確定要做,然后再想辦法!很快我們就想到了一個辦法,反過來做:滿足所有篩選條件的任務就一條,然后逐個的減少篩選條件,每少一個篩選條件,就增加一個適格任務。這樣理下來,共計25條數據就夠了,并沒有我們想象的多。從構思到文檔再到最后“造”完所有任務,差不多花了一個下午的時間而已。最后,戲劇性的是:出效果了!跑一遍,我們立馬發現了代碼里面的兩個bug。因為這種query查詢寫代碼的時候都“復制粘貼”的,十幾個條件,難免出錯。如果不是這樣跑一次,這些bug不知道什么時候能冒出來——因為我們自己用的篩選條件比較固定的,某些篩選條件從來沒用過。所以我問他:你之前說“跑得好好的”?他只能呵呵了。

 

第二件事,是在任務編輯頁面,我們要測試父子任務關系之間的自動化功能,這就需要比較復雜的一個“任務樹”做開發測試數據,好在我們是做了的。代碼review的時候,我在我這邊一跑,不對,就直接打回去了;過了一會,他跑過來,代碼沒問題啊?當時我們腦子都短路,沒想到其他,就先去看代碼去了,折騰了好久。在他電腦上跑,然后又在我電腦上跑,又是設斷點,又是看邏輯。

后來我突然靈光一閃,“是不是數據的問題?”

“嗯,有可能。但怎么確定呢?”

“你重新BuildDatabase再跑!”

果不其然,原來他自己跑的時候改動了數據,然后就忘了呀,一直就在已變動的數據上跑,當然沒問題了。虧得我們有BuildDatabase,可以隨時重建“基準”數據,否則,這種問題是相當花冤枉時間的!

這類似的情況其實很多很多,測試人員報bug之后,我估計開發人員最常用的一句臺詞就是:“我這里都能跑啊?!”所以問題80%都出在數據上——那為什么我們的數據就不能規范統一起來呢?

通過BuildDatabase,建立一個有序的可控的數據庫,我們才能夠在此基礎上進行一系列的(測試驅動的)文檔編寫、開發和測試活動。所以說,BuildDatabase是“測試驅動”的基石和保障。除此以外,BuildDatabase還可以在項目發布、模擬展示等方面發揮重要作用。

 

(我以前公司的集成測試環境這些,數據庫都是從生產環境中copy或截取的,我們需要的數據都是“自己造”,或者“自己找”的。這樣做能基本滿足開發測試需要,但中間總是很容易“出簍子”——正如我前面所說,一個test case可以跑一周。而且隨著數據增加,這個copy也越來越難啊,一次導幾百個G終究很累,所以好像是到了一定時候,還是得自行維護測試數據庫——但維護主要是數據結構上的,比如增減列之類的,數據本身是無法維護的。

我很好奇,除了我的builddatabase以外,有沒有其他比較可行的辦法?歡迎大家踴躍交流!)

 

老規矩,說項目進展情況。任務管理系統修了一些小bug,主要是“任務樹(關系)”可以向上向下自由展開了。接下來的主要工作是完善文檔,方便新加入的同學能迅速上手跑源代碼。唉~~~想到寫文檔就苦逼啊!我最愛代碼,恨文檔!!!

 


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()