问题
当待测试存储过程返回SQL行集的时候,如何判断测试结果是否通过。
设计
首先,创建一个临时数据库表,然后,调用待测存储过程并取回返回的行数,把它放到临时表里,计算临时表的聚合校验和(aggregate checksum),并把这个值与期望的校验值进行比较。
方案
设想有一个名为usp_HireAfter()的待测存储过程,它接受一个日期作为输入参数。这个存储过程从雇用日期晚于输入日期的那些记录表里选出所有的employee列(empID、empLast、empDOH):
create procedure usp_HiredAfter
@dt datetime
as
select * from tb1Employees where empDOH > @dt
首先,应该创建一个临时表,用于保存存储过程返回的SQL行集:
create table #results
(
empID char(3) primary key,
empLast varchar(35) not null,
empDOH datetime not null
)
注意:表名之前的#字符是用来表示这是一个临时表,然后可以调用待测存储过程并且把返回的行集存入临时表:
insert @results(empID,empLast,empDOH)
exec dbEmployees.dbo.usp_HiredAfter '10/25/2009'
接下来,计算临时表聚合校验和,并把实际值与期望值进行比较:
if(@@rowcount = 0)
set @actual = 0
else
select @actual = checksum_agg(binary_checksum(*)) from #results
if(@actual = 25527856)
print 'Pass'
else
print 'FAIL'
内建的SQL binary_checksum()函数返回SQL表里某一行的校验和。可以把它想象成用来代表某一行字符数据的一个整数值。checksum_agg()函数返回某一组值的聚合校验和。当它们一起使用时,其计算结果是一个胜于表征某个行值的整数值。
注解
许多存储过程都返回一个SQL行集对象。如何把待测存储过程实际返回的行集与期望值进行比较,并不是一目了然。一种方法是,创建一个测试用例数据存储,让它保存SQL行集的一个副本,这很难做到,而且有时候如果要处理的行集非常大这种方法根本适用不了。对于大多数测试情形来说,更好的办法是存储一个可以唯一映射到期望行集对象的整数值。SQL Server提供了binary_checksum()和checksum_agg()函数就是用来做这件事情的。因此,可以简单地比较两个行集的校验和,从而避免了直接对实际行集和期望行集进行烦琐的比较。这种方法同样也大大简化了测试用例的存储,因此可以不用存储一个复杂的行集数据,而只要保存一个整数值就可以了。
除了binary_checksum()函数,SQL还提供一个checksum()函数。checksum()函数以大小写不敏感方式计算返回值。对于自动化测试来说,通常应该使用binary_checksum()而不使用checksum()方法。
尽管测试存储过程的时候,通常比较期望校验和实际值校验和这种方法相比于其他方法有许多优点,但是这种方法有两个不足之处。首先,当期望的行集数据被保存为整数的时候,很难以可视化的方式检查你的测试用例数据。例如,如果以测试用例'10/25/2009'作为输入,受测存储过程返回的行集期望值如下:
-----------------------------------------------------------------------------------------------
e22 Baker 10/26/2009
e44 Zetta 10/26/2009
-----------------------------------------------------------------------------------------------
那么测试用例数据文件就会如以下的方式保存测试用例ID、测试用例输入和校验和的期望值
-----------------------------------------------------------------------------------------------
'0007','10/25/2009',25527856
-----------------------------------------------------------------------------------------------
这样不可能直接看到行集和它的校验和之间的关系。因此,必须小心维护文档说明每个检验和代表什么。使用校验和这种方法的第二个不足之处就是,通常需要更多的时间用于创建测试用例。对于待存储过程的每一个测试用例输入,必须判断结果行集应该是什么,然后计算这个假想行集的聚合二进制校验和。常见的错误是,通过调用待测存储过程然后计算返回行集的校验和。这么做只是验证了待测存储过程,相同的测试用例数据返回相同的结果,但这些结果有可能是不正确的。
当使用校验和这种技术的时候,需要记住在每次调用存储过程之前,删除临时表里的所有数据:
truncate table #results
在运行完所有的测试用例之后,应该删除整个临时表:drop table #results
另一种用于测试存储过程返回行集的方法是取返回的行数作为实际值和期望值
——把测试用例输入读入变量@caseID,@input,@expected
exec dbEmployees.dbo.usp_HiredAfter @input
set @actual = @@ROWCOUNT
if(@actual = @expected)
begin
set @resultLine = @caseID + ':Pass'
print @resultLine
end
else
begin
set @resultLine = @caseID + ':FAIL'
print @resultLine
end
使用@@rowcount函数取回待测存储过程实际返回了多少行,然后把这个值与期望的行数进行比较。显然,这种技术有严重的不足之处,最严重的就是只是检查待测存储过程返回了多少行,而没办法知道这些行是否包含了正确的SQL数据或它们的顺序是否正确,尽管如此,这种简单的技术还是很有用的,它还可以与采用检验和的技术一起使用,从而对测试套件进行更好的验证。