天天看點

在程式設計練習中學會設計和使用測試程式

  這是我和我的學生們c++程式設計課程中的一個練習。程式編寫得越來越大了,測試顯得越來越重要,如果還是照着以前一直對照練習要求寫程式,而不是按照工程要求去寫,永遠無法和實際工作去接軌。本文給出一個示例,展示在程式設計過程中,怎樣做到一邊寫程式,一邊開展測試的過程,這樣得到的程式中的各個“部件”可靠性得以保證。

【項目5-玩日期】

定義一個表示時間(包括年、月、日、時、分、秒)的結構體,然後完成下面的功能(可以在一個main函數中完成,也可以用函數求解,main函數調用即可):

(1)輸入一個時間(注意各部分資料的取值範圍)将輸入的時間儲存在一個結構體變量中;

(2)輸出該日在本年中是第幾天(注意閏年問題);

(3)輸出這是這一天中的第幾秒;

(4)輸出這是這一年中的第幾秒;

(5)求你輸入的時間d天後是哪年哪月哪日,将結果儲存在一個結構體變量中輸出;(你的萬天日期靠這個功能了)——插講一個故事。當年老賀由小孩兒過百日,想到自己的萬日在哪天。程式設計計算,結果剛過了十幾天,那個懊惱啊。第二個萬日得再等26年多,第三個萬日,誰敢說一定能過上?20歲左右的你,要算清楚了。在第(1)問中輸入你的生日及時辰,d值取為10000,可以算出你的萬日,大概在26歲多。

(6)求你輸入的時間s秒後是何日何時,将結果儲存在一個結構體變量中輸出;

  最後編好的程式的結構應該如下所示,其中所需要設計,一是存儲資料所用的資料結構——結構體,二是整個程式的架構,除了main()函數之外,還要有一系列的其他函數作為支撐。在嚴格的軟體工程中,需要提前将所需要的函數(工程中稱之為子產品)設計出來,而在學習文法階段,不妨也便宜行事,需要什麼寫什麼,這樣做更快一些。在此基礎上,main()函數隻要按照題目中的要求,或輸入,或調用函數,逐個地寫出來即可。

  是以,這個程式最後的結構會是:

  胖子是一口一口吃出來的,程式得一點一點寫出來,做一些,就測試一點,保證局部不要出問題。不要妄圖全寫完了才去測試,醫生說食物攝取過量,老百姓講是吃撐了。

  在這樣一種指導思想下,先完成第(1)個要求,主要是寫出自定義函數來。将需要多次用到的功能,例如,輸入中要保證範圍的要求,也“抽象”一下,做成函數getnum()。不少成員的取值範圍是确定的,但每月的天數并不都一樣有些麻煩,設計一個函數daysofmonth()實作,将有利于整個程式的簡潔。

  參考代碼可以如下:

  就寫作業而言,從做練習的角度,程式就是完成了。要完成測試,關鍵是保證輸入時資料取值範圍是否能夠得到保證,于是需要多次地啟動程式,輸入各種不同的時間,看是否能展現設計時的限制。需要考慮到的情形包括:

2013年1月20日3時4分5秒   //中規中矩的輸入

2012年3月31日3時4分5秒   //重點考察取日期的“邊界值”是否接受,類似地可以用其他月份檢查,還可以設計出多種情形

……

2013年2月29日3時4分5秒   //2013不是閏年,這個輸入會如何處理

2012年2月29日3時4分5秒   //2012是閏年,這個輸入會如何處理

2013年13月45日33時4分5秒 //各種的“搗亂”,這在測試中是必須的

  通過這樣的多次運作多次輸入檢視結果是可行的。但是,如果考慮一次運作程式,可以支援多次輸入對不同情形進行測試,那自然是更友善的事了。其實,寫一個循環,那也不是難事。事實上,這是工程中更常用的方式。

  在這種思路下,main()函數這樣寫。

  這樣,程式運作中的界面如下圖,這隻是測試所需要的一部分内容。這樣測試出的程式,品質信心必漲!好産品得經過嚴格的測試,放在程式設計中也是這樣。

  

在程式設計練習中學會設計和使用測試程式

  實作功能角度,增加一個函數dayofyear()即可。涉及到測試時,要靠着鍵盤輸入,那可就煩惱大了:改一點程式,輸入若幹資料測試,發現錯誤,改程式,再運作,輸入測試資料。這時,可以采用的方法是,用測試用到的資料直接初始化結構體。再進一步,一組測試資料,一起測試,用結構體數組儲存資料,測試過程做一個循環。

  實作了的函數和測試用的main()函數如下所示,實作任務(1)中的函數保留不動,它們是整個任務中的一部分,況且(2)任務可能會用到前面的勞動成果,删除不必要。

  參考程式如下:

  體會上面測試資料設計和測試程式(main()函數)設計中的用心,看下面運作測試的結果,生産好産品,需要這樣做。

在程式設計練習中學會設計和使用測試程式

  隻需要增加一個自定義函數

  相應的測試函數定義為:

  請體會上面的測試資料的設計,也可以設計出更好的來

  關于實作功能而言,主體在time afterdays(time t,int d)函數,這個求解有些麻煩,但是采用的算法統一從1月0日開始的思路,還是可以将複雜性降下來一些。

  先上程式:

  接着看測試程式,将時間與要經過的天數進行組合,從輸出中可以發現問題。當需要很多的測試資料時,期望結果實際上不能再由人手工計算,可以用一些輔助工具去完成。在一些資料庫系統中,有類似的現成的函數(在寫這個程式時企圖用wps 表格的公式,但不支援,記得excel裡有),還可以用系統函數計算的結果作對比,本文中,對用前面已經測試正确的函數dayofyear(),通過輸出日期是該年的第幾天幫助找到線索。

  另外,在上面的程式中,第114 - 116行加了注釋的部分,展現出的也是一種調試的手段:運作過程中适當輸出中間結果,進而判斷計算過程是否達到預期。這種方法與單步執行相比,資訊會來得快一些,不足之處是,資訊有時有些太多,适宜于對程式内在執行機制很清楚的程式員,需要有志做這些工作的同學追求。有些程式設計環境中,缺乏調試工具的支援,這樣的措施更顯得必要了。用這種方式,最後應将這些輸出資訊加上注釋,不要成為代碼中的一部分,或者幹脆删除了事。

  第(6)個任務和測試不再寫,作為選做吧。

最後,給出任務的最後解答

  有了經過測試的實作各功能的函數,隻是将main()函數按要求寫出即可,這樣不管有什麼樣的輸入,都不怕它耍着小脾氣,輸出錯結果了。

  貼程式:

  看下面的運作結果,老賀自己錯過了1萬天的慶祝,弟子們要記着老賀過2萬天請客的時候,都來随個份子。

在程式設計練習中學會設計和使用測試程式

【項目5擴充(選做】用結構體變量給定兩個時間,求(1)相差多少天?(2)相差多少秒?(略)

繼續閱讀