【问题标题】:tSQLt - Test that a column is output by a stored proceduretSQLt - 测试列是否由存储过程输出
【发布时间】:2014-10-16 14:05:40
【问题描述】:

我对 tSQLt 非常陌生,并且在真正应该非常简单的测试方面遇到了一些困难。

我在存储过程中执行的 SELECT 语句中添加了一列。

如何在 tSQLt 测试中测试该列是否包含在该存储过程的结果集中?

【问题讨论】:

    标签: tsqlt


    【解决方案1】:

    通常,在向存储过程的输出中添加列时,您需要测试该列是否存在并填充了正确的数据。因为我们要确保该列填充了相同的数据,所以我们可以设计一个测试来做到这一点:

    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/

    【讨论】:

    • 谢谢丹尼斯。我想我试图通过专注于一个新列来使问题过于复杂化,但通过测试程序的输出,默认情况下会测试该列
    【解决方案2】:

    如果您只对输出结构而不是内容感兴趣(并且您在 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+]'
    

    【讨论】:

    • 非常感谢您的详细回复,但很遗憾我们仍在为这个项目使用 2008 R2。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多