軟件工程練習:模塊化,單元測試,迴歸測試,TDD

這是《構建之法》實戰教學的一部分。適合做爲同窗們的第二個程序做業。html

第一個程序做業: 請看 「概論」 一章的練習,或者老師的題目,例如這個算法

 

做業要求:編程

軟件工程的做業愈來愈有意思了, 咱們在第一個做業中,用各類語言實現了一個命令行的四則運算小程序。 咱們看看若是要把咱們的小程序升級爲能穩定運行,解決用戶問題的軟件,應該怎麼作。 小程序

 

建議在作下面的題目的時候,採用結對編程的方式, 在練習中,讓同窗們學會模塊化編程,信息隱藏,接口設計,TDD,等。服務器

你們寫了很多四則運算的練習,這些代碼都各有特點,你們寫的 「軟件」 也有必定的用處。  若是咱們要把這個功能放到不一樣的環境中去 (例如,命令行,Windows 圖形界面程序,網頁程序,手機App),  就會碰到困難,  由於目前代碼的廣泛問題是代碼都散落在 main() 函數或者其餘子函數中,咱們很難把這些功能完整地剝離出來,做爲一個獨立的模塊知足不一樣的需求。 架構

 

咱們看到,不一樣的代碼解決不一樣層面的問題,有些是內部數據的計算 (例如四則運算);有些是和用戶輸入相關的 (例如 scanfcin,圖形界面的輸入輸出),有些是和數據的展示相關的 (例如 printf coutprintln,DrawText),有些是和程序所在平臺的架構相關的(例如 main 函數,程序倒計時的實現等)。 這就須要咱們對軟件的架構作一些整理和優化。框架

建議你們把四則運算的計算功能包裝在一個模塊中 (這個模塊能夠是一個類 Class,  一個DLL,等等), 爲了方便起見,咱們叫它 「計算核心」 模塊, 這個模塊至少在兩個地方可使用:模塊化

  1. 測試程序,這個能夠是一個命令行的程序,或者是JUnit 的框架,或者是Visual Studio 單元測試的框架。這樣,咱們在算法層級保證了這個模塊的正確性。 函數

  2. 實際的軟件,這是交付給最終用戶的軟件,有必定的界面和必要的輔助功能。單元測試

那麼這個「計算核心」模塊和使用它的其餘模塊之間是什麼關係呢?  它們要經過必定的API (Application Programming Interface) 來和其餘模塊交流。 這個API 接口應該怎麼設計呢?  (這是一個給有必定經驗和實力的同窗的題目), 爲了簡單,咱們能夠從下面的最簡單的接口開始:

            Calc()

            這個Calc 函數接受字符串的輸入(字符串裏就是運算式子,例如 「 5+3.5「  「7/8 – 3/8 」  「3 + 90 * (-0.3) 等等),這個模塊的返回值是一個字符串,例如,前面幾個例子的結果就是 ( 17.5「, 「 1/2」「-24「).

  

假設咱們用的是類,咱們的測試程序剛開始能夠是很是簡單的測試例子: (用僞代碼表示)

            String  result  = Core.Calc(「1 + 1」) ;

            Assert ( result == 「2」);  //咱們斷言 1 + 1 的結果必定是 2.

而後同窗們實現本身 Core 的這個功能。

第一階段目標 - 能把計算的功能封裝起來,經過測試程序和API 接口測試其簡單的加法功能。

加法成功以後,而後咱們再作減法, 乘法,除法,咱們假設目前爲止都是兩個操做數的運算,仍是很容易實現的。 因爲同窗們已經在本身之前的程序中實現了各類算法,這時候只要把實現的算法搬過來就行了。 你們能夠不斷增長測試的數量,在每實現一個新的功能的時候,要保證之前運行正確的例子繼續是正確的, 經過這樣的 迴歸測試,  來保證本身實現的函數一直是正確的 (請看書中關於單元測試,迴歸測試的內容)

  

第二階段目標 - 經過測試程序和API 接口測試其簡單的加減乘除功能。並能看到代碼覆蓋率。  

而後,更歡樂的狀況出現了, 多個運算符的運算,帶負數的運算。

 啊,等一下,若是咱們考慮這些狀況的話, 咱們這個模塊有一些參數要設置,例如,最多幾個運算符,能帶括號麼?數據範圍是多少,還要設置計算的精度(保留幾位小數,必須是用分數形式表示麼,等等), 這是由什麼API 來決定呢?   咱們能夠擴展 Calc() 的定義,讓它接受一個新的參數 「precision」,  或者咱們能夠啓用一個新的函數 Setting()。

若是我想表示:

    最多4 個運算符

    數值範圍是 -1000 到 1000

    精度是小數點後兩位

怎麼經過API 告訴咱們的模塊呢?  咱們固然能夠用函數的參數直接傳遞,可是參數的組合不少,怎麼定義好參數的規範呢?   建議你們考慮用 XML 來傳遞這些參數。

增長了新的Setting() 函數以後,咱們要讓模塊支持這樣的參數,同時,還要保證原來的各個測試用例繼續正確地工做

 

 

第三階段目標 - 經過測試程序和API 接口測試對於各類參數的支持。並能看到代碼覆蓋率。   

這個時候,若是輸入是有錯誤的,例如 「1 ++ 2」, 在數值範圍是 -1000 .. 1000 的時候,傳進去 「10000 + 32768 * 3」,  或者是 「 248.04 / 0」  怎麼辦? 怎麼告訴函數的調用者 「你錯了」?  把返回的字符串定義爲 「-1」 來表示? 那麼若是真的計算結果是 「-1」 又怎麼處理呢?

 

建議這個時候,咱們要定義各類異常 (Exception), 讓 Core 在碰到各類異常狀況的時候,能告訴調用者 - 你錯了! 固然,這個時候,咱們一樣要進行下面的增量修改:

  定義要增長什麼功能 - 例如:支持 「運算式子格式錯誤」 異常

       寫好測試用例,傳進去一個錯誤的式子,指望能捕獲這個 異常。 若是沒有,那測試就報錯。

       在 Core 模塊中實現這個功能

       測試這個功能

       同時測試全部之前的功能,保證之前的功能還能繼續工做 (沒有 regression)

       確認功能完成,繼續下一個功能

 

第四階段目標 - 界面模塊,測試模塊和核心模塊的鬆耦合。

既然各組各組同窗都寫了高質量的各個模塊,並且模塊之間的關係是明肯定義的,一致的,那麼,小組A 的測試模塊就能夠測試小組B 的核心模塊;小組C 的用戶界面模塊就能夠和小組B 的核心模塊結合起來,正常運行。對吧?! 那咱們就讓兩個小組 (A,B) 在一塊兒,測試一下下面的狀況:

      - A 的核心模塊, 加上B 的測試模塊和用戶界面模塊

      - B 的核心模塊,加上A 的測試模塊和用戶界面模塊

兩組同窗分析合併以後出現了什麼問題,爲什麼會出現這樣的問題?如何改進?   而且改進各類模塊中的 bug

(請看北航同窗的做業心得:http://www.javashuo.com/article/p-riylxjvn-kp.html )

 

第五階段目標 - 經過增量修改的方式,改進程序, 完成對各類錯誤狀況的處理。

選擇兩組程序中高質量的模塊,增長必要的功能,把全部代碼簽入源代碼管理服務器, 同時,把這個軟件發佈出來。

(請看北航一個同窗的嘗試:http://www.javashuo.com/article/p-rzomntcj-kn.html

 

第六階段目標 - 如何把這些模塊重用到別的相關項目中去。

例如,如今你們要作一個 【24點遊戲】:

有四個數字,經過加減乘除括號等四則運算,把四個數字組成一個算式,結果是 24。 這個遊戲有兩檔難度,入門級:數字在 1..10 之間; 高級:數字在 1..99 之間

可用命令行或本地GUI 或 網頁界面的方式實現這個遊戲

 

咱們要從頭開始寫全部的程序麼?這個題目須要的一些功能和咱們花了很長時間作的 「四則運算」 模塊有很多相似之處, 那麼,如何把現有模塊通過少許的改動,快速地構建成爲一個 24 點遊戲所需的模塊呢? 作到這些,並能總結一些規律,軟件工程課程就有點摸到 「工程」 的邊了!

相關文章
相關標籤/搜索