软件工程练习:模块化,单元测试,回归测试,TDD
這是《構建之法》實戰教學的一部分。適合作為同學們的第二個程序作業。
第一個程序作業: 請看 “概論” 一章的練習,或者老師的題目,例如這個。
作業要求:
軟件工程的作業越來越有意思了, 我們在第一個作業中,用各種語言實現了一個命令行的四則運算小程序。 我們看看如果要把我們的小程序升級為能穩定運行,解決用戶問題的軟件,應該怎么做。
建議在做下面的題目的時候,采用結對編程的方式, 在練習中,讓同學們學會模塊化編程,信息隱藏,接口設計,TDD,等。
大家寫了不少四則運算的練習,這些代碼都各有特色,大家寫的 “軟件” 也有一定的用處。? 如果我們要把這個功能放到不同的環境中去 (例如,命令行,Windows 圖形界面程序,網頁程序,手機App),? 就會碰到困難,? 因為目前代碼的普遍問題是代碼都散落在?main() 函數或者其他子函數中,我們很難把這些功能完整地剝離出來,作為一個獨立的模塊滿足不同的需求。
我們看到,不同的代碼解決不同層面的問題,有些是內部數據的計算 (例如四則運算);有些是和用戶輸入相關的 (例如 scanf,cin,圖形界面的輸入輸出),有些是和數據的展現相關的 (例如 printf ,cout,println,DrawText),有些是和程序所在平臺的架構相關的(例如 main 函數,程序倒計時的實現等)。 這就需要我們對軟件的架構做一些整理和優化。
建議大家把四則運算的計算功能包裝在一個模塊中 (這個模塊可以是一個類 Class,? 一個DLL,等等), 為了方便起見,我們叫它 “計算核心”?模塊,?這個模塊至少在兩個地方可以使用:
測試程序,這個可以是一個命令行的程序,或者是JUnit 的框架,或者是Visual Studio 單元測試的框架。這樣,我們在算法層級保證了這個模塊的正確性。
實際的軟件,這是交付給最終用戶的軟件,有一定的界面和必要的輔助功能。
那么這個“計算核心”模塊和使用它的其他模塊之間是什么關系呢?? 它們要通過一定的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
(請看北航同學的作業心得:https://www.cnblogs.com/SivilTaram/p/4859934.html )
第五階段目標 - 通過增量修改的方式,改進程序, 完成對各種錯誤情況的處理。
選擇兩組程序中高質量的模塊,增加必要的功能,把所有代碼簽入源代碼管理服務器, 同時,把這個軟件發布出來。
(請看北航一個同學的嘗試:https://www.cnblogs.com/skyxuan/p/4858486.html)
第六階段目標 - 如何把這些模塊重用到別的相關項目中去。
例如,現在大家要做一個 【24點游戲】:
有四個數字,通過加減乘除括號等四則運算,把四個數字組成一個算式,結果是 24。 這個游戲有兩檔難度,入門級:數字在 1..10 之間; 高級:數字在 1..99 之間
可用命令行或本地GUI 或 網頁界面的方式實現這個游戲
我們要從頭開始寫所有的程序么?這個題目需要的一些功能和我們花了很長時間做的 “四則運算” 模塊有不少類似之處, 那么,如何把現有模塊經過少量的改動,快速地構建成為一個 24 點游戲所需的模塊呢? 做到這些,并能總結一些規律,軟件工程課程就有點摸到 “工程” 的邊了!
總結
以上是生活随笔為你收集整理的软件工程练习:模块化,单元测试,回归测试,TDD的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CSDN 统一标签设计 征求反馈
- 下一篇: 美国大学计算机专业排名2014,2014