处理“方法抛出异常”的情况
问题
如何测试一个抛出异常的方法。
设计
在测试用例数据文件中嵌入一个特殊的字符串标记,用来表示应该由一个异常被抛出,把待调用的方法放到一个try块里,这样如果有异常抛出,就可以捕获它。
方案
在测试程序数据里加一个"Exception"标记,作为期望值。
0004:GeometricMean:1 2 4 8 16 32:6.6569
0005:GeometricMean:0 0 0 0 :Exception
0006:GeometricMean:2 4 8:4.0000
然后就可以在测试程序的主循环里像下面这样进行处理:
MathLib.Methods m = new MathLib.Methods(); if(tokens[3] == "Exception") { try { actual = m.GeometricMean(input); } catch(Exception ex) { Console.WriteLine(caseID + " Pass"); Continue; } Console.WriteLine(caseID + " *FAIL* no exception throw"); } else { //采用常规的测试逻辑 } |
注解
一种常见的情况是,很多方法在处理某些给定的输入时会抛出异常。例如,某个方法针对它的输入参数做除法操作,如果这个参数值为0,就可能会抛出一个异常。在本例中,修改最初的GeometricMean()方法。如果传给它的参数值都是0,则抛出一个异常。通过检查测试用例中是否有"Exception"字符串来确定上述特殊的输入值。如果找到,就转到try块里执行GeometricMean()调用。如果像期望的那样,有一个异常抛出,程序的控制权就会转向catch块,并且打印出的结果为"pass"。接下来会执行continue语句,这时候就会转向下一个测试用例。如果调用GeometricMean()没有抛出异常,程序的控制权会转向下面这条语句:
Console.WriteLine(caseID + " *FAIL* no exception throw");
请注意,不要把那些调用不抛出异常的待测方法的代码放到try块里,因为如果有异常被抛出的话,就会得到"pass"的结果。如果把处理抛出异常的情况和测试套件的"正常"处理逻辑含有成在一起处理,有可能会相当棘手。有鉴于此,好的策略就是创建两个不同的轻量级测试套件——一个用来测试那些不抛出异常的测试用例,一个用来测试那些抛出异常的测试用例。
前面的这个方案只能测试是否有异常被抛出,而不能测试是否是某个特定的异常。某些情况下,可能想要检查某个特定的异常是否被抛出。一种方法是在测试用户文件中嵌入异常信息,并且在测试套件中检验它。例如,设想GeometricMean()方法包含以下代码:
if (denominator == 0)
throw new Exception("Invalid division");
那么可以创建下面这个测试用例:
0005:GeometricMean:0 0 0 0:Invalid division
然后在测试程序的主循环里加入测试代码:
expected = tokens[3]; //"Invalid division" try { actual = m.GeometricMean(input); } catch(Exception ex) { if(ex.Message == expected) { Console.WriteLine(caseID + " Pass;Correct exception"); Continue; } else { Console.WriteLine(caseID + " *FAIL*;Wrong exception"); } } Console.WriteLine(caseID + " *FAIL*;no exception throw"); |