l

2013年1月16日 星期三

需求變來變去的情況下需要寫單元測試嗎?

Jan. 14 11:13~14:00

image

最近有一位鄉民甲問Teddy一個問題…

鄉民:我宣導了一陣子,但是我們團隊成員還是不願意寫單元測試。

Teddy:為什麼?

鄉民甲:因為他們認為我們的需求經常變動,除了來自於客戶需求變更之外,更常遇到一些熱心的長官提出自己寶貴的意見。長官的意見你要不要聽?當然要啊,所以我們就需要一直去修改程式來配合各方人馬的要求。在這種情況下,系統功能都還沒穩定,如果要開發人員寫單元測試,那麼單元測試勢必也要跟著需求變更一起改變。團隊成員普遍認為:「修改功能的時間都沒有了,哪有時間去修改單元測試啊」。所以,乾脆不寫單元測試,這樣比較不會綁手綁腳的。

Teddy:那…請問「當需求穩定之後」,團隊就願意寫單元測試了嗎?

鄉民甲:ㄟ…還是不願意。

Teddy:這…為什麼?

鄉民甲:可能是因為「平常沒有養成寫單元測試的習慣,所以當需求穩定之後也不會想要寫」。此外,「當需求穩定之後」大家會覺得「功能也沒什麼大問題」,所以幹嘛去補寫單元測試呢?

***

請思考以下幾個問題:

  1. 程式設計師是否需要擔負起「寫出功能正確程式」的責任?
  2. 承上題,如果覺得不需要,請立即轉台。如果需要,那麼程式設計師如何「證明」他所寫的程式是對的?
    • 用嘴巴喊。我用「生命 人格」擔保,我寫出來的程式絕對沒有問題。很遺憾地,程式設計師的人格通常…嗯嗯…挑眉質疑
    • 人工測試。我寫程式的時候自己有測過了,OK的。問題是,程式設計師採用手動測試的方法,通常只能測試到目前正在修改的功能是否正確,但卻無法確定此次修改是否有打破原本正常執行的其他功能(沒有做迴歸測試)。所以,很可能導致「改一個地方,錯十個地方而且還沒人發現」的現象。
    • 自動化單元測試。有了自動化單元測試,可以在每次修改程式之後重複執行這些單元測試(所謂的迴歸測試),可以減少「改一個地方,錯十個地方而且還沒人發現」的現象。

現在問題來了,為什麼程式設計師不願意寫單元測試?原因真的是如鄉民甲所說的:「沒時間」嗎?Teddy認為沒時間應該只是一種表象,真正的根本原因請參考下圖:

螢幕快照 2013-01-14 下午12.34.47

  • 開發人員認為他們「沒時間寫自動化單元測試」,導致採取「選擇性人工手動測試」。
  • 因為採用「選擇性人工手動測試」,所以無法執行迴歸測試,因此導致「不易立即找出修改的side-effect」且當bug發生時,需要「很長的debug時間」。
  • 「不易立即找出修改的side-effect」導致
    • 需要「很長的debug時間」
    • 「Bug變多(軟體品質不佳)」
    • 「降低軟體的Modifiability」
  • 「很長的debug時間」會
    • 降低「降低軟體的Modifiability」
    • 導致「很長的開發時間」
  • 「Bug變多(軟體品質不佳)」與「降低軟體的Modifiability」導致 「產品無法及時上市」。
  • 「很長的開發時間」導致「沒時間寫程式」。
  • 「沒時間寫程式」導致「沒時間寫自動化單元測試」。

雖然看起來扯得有點遠,但是「產品無法及時上市」是Teddy認為「沒時間寫自動化單元測試」所造成的問題(Problem)。至於「沒時間寫自動化單元測試」的原因(root cause)則是以下兩點:

  • 設計不良導致單元測試很難寫:如果一個method或是function有2千行,針對這個method或是function的單元測試就很難寫。所以,有時候程式不好測,是因為設計不良的問題。可能是long method(太長的method),或是模組化不夠、或是模組之間的相依性設計得不好。
  • 不會寫(做)自動化單元測試:大多數的開發人員其實不知道要如何撰寫單元測試,也不知道要如何利用持續整合來做迴歸測試。不知道怎麼做單元測試,自然不會想要去做啊。

***

怎麼辦

回歸到本篇標題所提到的問題:「需求變來變去的情況下需要寫單元測試嗎?」不但需要,而且是更加需要。因為「需求變來變去」就代表開發人員要不斷地修改程式。既然要不斷地修改程式,在沒有自動化單元測試的幫助之下,就非常可能造成「不易立即找出修改的side-effect」與「很長的debug時間」,因此導致「很長的開發時間」,又造成「沒時間寫程式」更不可能有時間寫自動化單元測試的惡性循環。

看到這邊鄉民們可能會想:可是寫測試要花時間啊,這一點Teddy怎麼都沒提到?

沒錯,寫測試需要花時間,改測試也需要花時間,而且有時候甚至需要花費比寫production code還要多的時間。但是,這些花費的時間,是可以賺回來的

  • 比較容易立即找出修改所造成的side-effect,因此大幅減少花費在debug上面的時間。
  • 可以支持refactoring或是其他修改要求,增加系統的modifiability。
  • 軟體的品質(bug的數量)可以維持在一個可控制或是說可接受的範圍之內,讓團隊成員與客戶對軟體保持一定的信心,團隊成員也比較願意動手改程式。

***

鄉民:講了這麼多,我還是不知道要如何做單元測試啊 ?

Teddy:很簡單,請報名參加單元測試與持續整合實作班」。

***

友藏內心獨白:又被置入性行銷了熱戀

3 則留言:

  1. 我的建議是課程裡加入跟Web App有關的單元測試方法,和Rich client相比,Web前端遠比後端難測,後端有時大多是簡單的DB CRUD,單元測試相對好寫(不過測試執行時間長),在Web App越來越普遍的情況下,單純OO的測試方法不容易招生到人。

    回覆刪除
  2. Hi Spirit Du,

    這門課主要的目的是(1) 介紹單元測試的基本概念、測試涵蓋率、如何讓單元測試比較容易寫、如何避免時好時壞的單元測試 (2) 持續整合基本概念與版控系統之間的關係 (3) Jenkins 持續整合系統應用實作。

    我同意Web 測試很難,但這應該是另外一門課。我之前的經驗是,Web 前端的測試是用RobotFramework來做『功能測試』,並沒有幫 Web UI 做單元測試。

    『用RobotFramework做功能測試』以及『手機 App 功能測試』的課程目前正在規劃中,也許2013下半年(6月之後)就會推出。

    回覆刪除
  3. 其實現在的前端有很多程式(JavaScript),要說功能測試也行,或是針對JavaScript程式的單元測試,昨天正好燾佑介紹了一個QUnit,有點接近我在想的東西。Web難測最主要的原因是有時候model很難抽乾淨,後台是主要的data model,但UI會有些presentation model的東西,所以我所謂的單元測試方法是指presentation model,不完全是整個頁面的功能去測。

    回覆刪除