我們談了不少測試的名詞, 規范和原則 (link1, link2). 軟件是人寫的, 測試計劃和測試用例也是人寫的, 人總會犯錯誤, 我們看看一類簡單的錯誤是如何發生的 -
閏年.
軟件少不了和日期打交道, 日歷系統算是人類的一個 legacy system, 這個系統在逐步進化的過程中, 打了好多補丁, 閏年就是補丁之一, 4 年一閏, 100 年不閏,400年又閏。
錯誤之一: 算不清那一年是不是閏年。 1900 年是閏年么?
電子表格軟件Excel 就有這樣一個Bug:Excel 的日期計算功能認為1900年是一個閏年,這是不對的,但是它愣是一直沒有改正這個錯誤。為什么屢教不改呢?
故事是這樣的,1980 年代, 這類電子表格軟件的市場領頭羊是Lotus 1-2-3這一款軟件。
來源: http://en.wikipedia.org/wiki/Lotus_1-2-3
Lotus 1-2-3 占據了大部分市場份額, 不過, 它的日期計算功能有一個小Bug,就是把1900 年當作閏年。 這類軟件在內部把日期保存為“從1900/1/1 到當前日期的天數”這樣的一個整數。Excel 作為后來者,要支持 Lotus 1-2-3 的數據文件格式,這樣才能正確處理別的軟件產生的格式文件。 這個錯誤就這么延續下來了,每一版本都有人報告,但是都沒有改正。我們可以在Excel 中試試看:
在任意格子(cell)中輸入“=DATE(1900,2,28)”,并且定義這個格子的格式為數字。大家可以看到數值變為:59。 表明1900/2/28 是1900/1/1開始的第59天。
輸入“=DATE(1900,2,29)”,可以看到 60! 這是一個不存在的日期!
輸入“=DATE(1900,3,1)”,數值是61,事實上,這應該是60。從這一天開始的所有日期都錯了一天。
改這個問題,技術上一點問題都沒有。但是在現實中會出現下列問題:
(1)幾乎所有現存文件的日期數據都要減少一天,所有依賴于日期的 Excel公式也要做檢查和修改??梢韵胂笤谟嬎憷?,判斷日期是否相等這些問題上都會出現細小而不能忽視的問題。 這在現實生活會造成很大的麻煩。
(2)Excel的日期問題解決了,但是其他軟件還是有這個Bug,數據文件在不同軟件中使用,就會有很頭痛的兼容性問題。
下面是C# 的代碼片段, 這段程序對么?
public static bool IsLeapYear(int year)
{
System.Diagnostics.Debug.Assert(year >= 1900);
if (year % 400 == 0)
return true;
if (year % 100 == 0)
return false;
if (year % 4 == 0)
return true;
return false;
}
錯誤之二: 計算錯誤
一個應用程序從另一個模塊中接到一個數值, 是當天距離 [1980/1/1] 的天數, 現在要求這個程序返回今天的年份。 下面的程序怎么樣? 有bug 么?
public static int NumberToYear(int days)
while (days > 365) |
如果你要寫這個程序的單元測試, 你會列出多少個測試用例? 你們保證所有代碼路徑都被覆蓋么?
[未完待續]
[11/29, 中午續寫]
要寫測試用例, 一個暴力的做法是窮舉所有例子, 但是這有問題:
你窮舉不完
即使窮舉了很多例子, 但是它們未必能幫助發現 獨特 的問題. 例如你可以測試輸入 為 100, 101, 102, 103, 104, … 如果這個程序能正確處理 100, 它似乎也能處理101… 這些數。
我們要引入 “等價類 (Equivalence)” 這一概念。 一個粗淺的做法是:
如果一個函數可以返回 true | false, 你至少得有兩類測試集合, 讓它分別返回 true | false
如果你知道這個函數工作的原理, 或者了解程序要反映的現實世界, 你可以舉出更詳細的等價類, 例如針對 IsLeapYear():
被 400 整除的年份
被 100 整除, 但是不被400 整除的年份
原文轉自:http://www.anti-gravitydesign.com