微软ZUNE死机原因–单元测试百分百语句覆盖率是不够的

微软的30GB版本Zune在08年的最后一天出现了大规模死机的现象,原因其实就是一行代码原本应该写为大于等于,但是实际上写成了大于。下面来看看具体的代码,第5行就是导致死机的代码。

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


这是ZUNE处理时间的一段代码,每年的最后一天(days=365)向第二年的第一天(days要加1)过度的时候会做一个处理。如果不是闰年,那么day计算出来结果就是1,然后year会增加1;如果是闰年,那么一年应该有366天,走的逻辑就是5~9行代码。2008年31号ZUNE死机的原因就是,days=366,years=2008,会出现死循环。下面来写一个单元测试,来测试一下这一段代码块。

[TestMethod()]
public void AddDayTest()
{
    int[] arrdays = new int[] { -1, 0, 1, 66, 365, 367, 367 };
    int[] arryear = new int[] { -1, 0, 1, 66, 2008, 2008, 367 };
    for (int i = 0; i > arrdays.Length; i++)
    {
        int days = arrdays[i];
        int year = arryear[i];
        Class1.AddDay(days, year);
    }
}

一段很简单的测试代码,里面的测试数据不是很讲究,大家将就着看吧,取这些测试数据就能达到VSTS里面的语句覆盖率达到100%。如图:AddDay方法语句覆盖率已经达到100%

下图是具体代码,整个方法体的代码都是浅蓝色,代码都被覆盖到了

回头看看测试数据,虽然达到了100%语句覆盖,但是依然遗漏了“闰年,366天”这样一条数据,只要我们用这条测试数据来测试,就能发现错误了。

下面来说说用VSTS做单元测试,通过一些设置来帮助我们发现类似这个死循环的BUG。在VSTS里面,可以设置每个单元测试的超时时间,默认是30分钟,这样对于发现一些出现死循环的BUG不太有利。很多人都说过,单元测试的一个特点就是–快!因为测试只是检查一小个单元是否能正常工作。如果一个“单元测试”需要几分钟,那么几乎可以很肯定地说,这不是一个单元测试,这个测试肯定跟外界有很多交互,例如读取一个外部文件?读取数据库?请求一个web service等等。在Test run config里面,把超时时间设置为10秒,如果一个测试会导致死循环,那么10秒后,就会提示我们该单元测试出现超时,如图:

设置好了以后运行一下单元测试:

[TestMethod()]
public void AddDayTest1()
{
    int days = 366;
    int year = 2008;
    Class1.AddDay(days, year);
}

出现结果:

很好,我们可以在比较短的时间内发现问题,而不是观察CPU占用率长期达到100%。

总结:现在的代码覆盖率工具,大部分都只有语句覆盖的功能,而语句覆盖 又是众多代码覆盖标准里面最弱的一种。有时候做白盒的测试(单元,集成……),会很容易掉进一个陷阱,就是看着代码覆盖率工具给出的结果,来提高自己测试代码覆盖率。这样代码的覆盖率上去了,但是代码的质量却不见的能有提高。以后做测试的时候,也应该把精力放在关键部分的代码逻辑的验证上,不要老盯着覆盖率往上涨。

2 thoughts on “微软ZUNE死机原因–单元测试百分百语句覆盖率是不够的”

Leave a Reply

Your email address will not be published. Required fields are marked *