关于闰年的测试

     很多软件都实现了日期这一功能,日历系统算是人类的一个legacy system。在此系统逐步进化中,也衍生出一些问题,例如“千年虫”、”闰年虫”。其中闰年虫是人们对于一些电脑在设计时未考虑闰年因素,将所有年份的2月都默认为有29天或者28天而出现运算错误的一种形象叫法,因为在英文里Bug兼有臭虫、缺陷等含义,所以这一缺陷被称为“闰年虫”。

     在2012年2月底,广州“闰年虫”爆发,上千的士因计价器出问题而停运,如图所示:

      就连著名的微软也会出现”闰年虫”的失误,微软Windows Azure云平台若干子区域受“闰年虫”影响致许多客户12至24个小时无法使用服务。根据Windows Azure服务仪表板显示,从UTC时间2012年2月29日凌晨到3月1日早上,大量的子区域服务和全球性服务发生了超过24小时的中断。

      因此如何正确判断闰年是一个十分重要的问题,下面是C# 的代码片段:

 1 public static bool IsLeapYear(int year)
 2 {
 3     System.Diagnostics.Debug.Assert(year >= 1900); 
 4     if (year % 400 == 0)
 5         return true;
 6     if (year % 100 == 0)
 7         return false;
 8     if (year % 4 == 0)
 9         return true;
10     return false; 
11 }

     如果你要写这个程序的单元测试, 你会列出多少个测试用例?  一个”笨”方法就是进行穷举,可又会面临以下问题:

    1. 穷举不完
    2. 即使穷举了很多例子, 但是它们未必能帮助发现独特的问题,并不具有代表性

     因而我们要引入 “等价类 (Equivalence)” 这一概念。所谓等价类是指输入域的某个互不相交的子集合,所有等价类的并集便是整个输入域,目的在于测试用例的无冗余性。 一个粗浅的做法是:

如果一个函数可以返回 true | false, 你至少得有两类测试集合, 让它分别返回 true | false

     如果你知道这个函数工作的原理, 或者了解程序要反映的现实世界, 你可以举出更详细的等价类, 例如针对 IsLeapYear()的测试用例如下:

被 400 整除的年份

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

被 100 整除, 同时被400 整除的年份

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

被 4 整除, 同时被100 整除的年份

偶数, 不被4 整除的年份

奇数年份

其它非法输入的年份

      另外程序员都知道程序经常在边界条件附近出错, 针对IsLeapYear(), 你可以得出下面两个测试用例:

设计允许的最小的年份

设计允许的最大的年份

     总而言之,选取正确而又合适的测试用例是测试程序有无bug的必备条件。除此之外,判断是否为闰年的代码也可以简化如下:

1 bool isLeapYear( int year )
2 {
3     return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
4 } 

 

posted on 2015-03-14 11:30  华语  阅读(1597)  评论(0编辑  收藏  举报

导航