現代軟件工程講義 9 測試 關于閏年的測試

發表于:2012-01-05來源:博客園作者:SoftwareTeacher點擊數: 標簽:軟件測試
我們談了不少測試的名詞, 規范和原則 (link1, link2). 軟件是人寫的, 測試計劃和測試用例也是人寫的, 人總會犯錯誤, 我們看看一類簡單的錯誤是如何發生的 - 閏年. 軟件少不了和日期打交道, 日歷系統算是人類的一個 legacy system, 這個系統在

  我們談了不少測試的名詞, 規范和原則 (link1, link2). 軟件是人寫的, 測試計劃測試用例也是人寫的, 人總會犯錯誤, 我們看看一類簡單的錯誤是如何發生的 -

  閏年.

  軟件少不了和日期打交道, 日歷系統算是人類的一個 legacy system, 這個系統在逐步進化的過程中, 打了好多補丁, 閏年就是補丁之一, 4 年一閏, 100 年不閏,400年又閏。

  錯誤之一: 算不清那一年是不是閏年。 1900 年是閏年么?

  電子表格軟件Excel 就有這樣一個Bug:Excel 的日期計算功能認為1900年是一個閏年,這是不對的,但是它愣是一直沒有改正這個錯誤。為什么屢教不改呢?

  故事是這樣的,1980 年代, 這類電子表格軟件的市場領頭羊是Lotus 1-2-3這一款軟件。

image

  來源: 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)
{
    int year = 1980; /* start with 1980 */
    System.Diagnostics.Debug.Assert(days >= 0);

    while (days > 365)
    {
        if (IsLeapYear(year))
        {
            if (days > 366)
            {
                days -= 366;
                year ++;
            }
        }
        else
        {
            days -= 365;
            year ++;
        }
    }
    return year;
}   

  如果你要寫這個程序的單元測試, 你會列出多少個測試用例? 你們保證所有代碼路徑都被覆蓋么?

  [未完待續]

  [11/29, 中午續寫]

  要寫測試用例, 一個暴力的做法是窮舉所有例子, 但是這有問題:

  你窮舉不完

  即使窮舉了很多例子, 但是它們未必能幫助發現 獨特 的問題. 例如你可以測試輸入 為 100, 101, 102, 103, 104, … 如果這個程序能正確處理 100, 它似乎也能處理101… 這些數。

  我們要引入 “等價類 (Equivalence)” 這一概念。 一個粗淺的做法是:

  如果一個函數可以返回 true | false, 你至少得有兩類測試集合, 讓它分別返回 true | false

  如果你知道這個函數工作的原理, 或者了解程序要反映的現實世界, 你可以舉出更詳細的等價類, 例如針對 IsLeapYear():

  被 400 整除的年份

  被 100 整除, 但是不被400 整除的年份

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97