【发布时间】:2014-10-16 14:05:40
【问题描述】:
我对 tSQLt 非常陌生,并且在真正应该非常简单的测试方面遇到了一些困难。
我在存储过程中执行的 SELECT 语句中添加了一列。
如何在 tSQLt 测试中测试该列是否包含在该存储过程的结果集中?
【问题讨论】:
标签: tsqlt
我对 tSQLt 非常陌生,并且在真正应该非常简单的测试方面遇到了一些困难。
我在存储过程中执行的 SELECT 语句中添加了一列。
如何在 tSQLt 测试中测试该列是否包含在该存储过程的结果集中?
【问题讨论】:
标签: tsqlt
通常,在向存储过程的输出中添加列时,您需要测试该列是否存在并填充了正确的数据。因为我们要确保该列填充了相同的数据,所以我们可以设计一个测试来做到这一点:
CREATE PROCEDURE MyTests.[test stored procedure values MyNewColumn correctly]
AS
BEGIN
-- Create Actual and Expected table to hold the actual results of MyProcedure
-- and the results that I expect
CREATE TABLE MyTests.Actual (FirstColumn INT, MyNewColumn INT);
CREATE TABLE MyTests.Expected (FirstColumn INT, MyNewColumn INT);
-- Capture the results of MyProcedure into the Actual table
INSERT INTO MyTests.Actual
EXEC MySchema.MyProcedure;
-- Create the expected output
INSERT INTO MyTests.Expected (FirstColumn, MyNewColumn)
VALUES (7, 12);
INSERT INTO MyTests.Expected (FirstColumn, MyNewColumn)
VALUES (25, 99);
-- Check that Expected and Actual tables contain the same results
EXEC tSQLt.AssertEqualsTable 'MyTests.Expected', 'MyTests.Actual';
END;
通常,您正在测试的存储过程依赖于其他表或其他存储过程。因此,您也应该熟悉 FakeTable 和 SpyProcedure:http://tsqlt.org/user-guide/isolating-dependencies/
【讨论】:
如果您只对输出结构而不是内容感兴趣(并且您在 SQL2012 或更高版本上运行),另一个选择是在测试中使用 sys.dm_exec_describe_first_result_set_for_object。
此 dmo(动态管理对象)返回有关为给定对象返回的第一个结果集的各种信息。
在下面的示例中,我只使用了此 dmo 返回的一些列,但如果您的输出包含十进制数据类型,则其他列可用。
在这个测试中,我用我希望如何返回每列的信息填充一个临时表 (#expected),例如名称、数据类型和可空性。
然后我从 dmo 中选择等效列到另一个临时表 (#actual)。
最后我用tSQLt.AssertEqualsTable来比较两个表的内容。
说了这么多,虽然我经常编写测试来验证视图或表的结构(使用tSQLt.AssertResultSetsHaveSameMetaData),但我从来没有发现需要只测试过程的结果集合同。 Dennis 是正确的,您通常有兴趣断言结果集中的各个列都填充了正确的值,并且当您涵盖该功能时,您应该已经涵盖了每一列。
if object_id('dbo.myTable') is not null drop table dbo.myTable;
go
if object_id('dbo.myTable') is null
begin
create table dbo.myTable
(
Id int not null primary key
, ColumnA varchar(32) not null
, ColumnB varchar(64) null
)
end
go
if object_id('dbo.myProcedure') is not null drop procedure dbo.myProcedure;
go
create procedure dbo.myProcedure
as
begin
select Id, ColumnA, ColumnB from dbo.myTable;
end
go
exec tSQLt.NewTestClass @ClassName = 'myTests';
if object_id('[myTests].[test result set on SQL2012+]') is not null drop procedure [myTests].[test result set on SQL2012+];
go
create procedure [myTests].[test result set on SQL2012+]
as
begin
; with expectedCte (name, column_ordinal, system_type_name, is_nullable)
as
(
-- The first row sets up the data types for the #expected but is excluded from the expected results
select cast('' as nvarchar(200)), cast(0 as int), cast('' as nvarchar(200)), cast(0 as bit)
-- This is the result we are expecting to see
union all select 'Id', 1, 'int', 0
union all select 'ColumnA', 2, 'varchar(32)', 0
union all select 'ColumnB', 3, 'varchar(64)', 1
)
select * into #expected from expectedCte where column_ordinal > 0;
--! Act
select
name
, column_ordinal
, system_type_name
, is_nullable
into
#actual
from
sys.dm_exec_describe_first_result_set_for_object(object_id('dbo.myProcedure'), 0);
--! Assert
exec tSQLt.AssertEqualsTable '#expected', '#actual';
end
go
exec tSQLt.Run '[myTests].[test result set on SQL2012+]'
【讨论】: