如何使用tSQLt测试更新表(与返回结果集)的TSQL存储过程

时间:2016-03-15 15:44:10

标签: tsql testing stored-procedures tsqlt

请问tSQLt专家是否可以尝试测试一种不会返回任何内容但在表中执行字段更新的存储过程的方法?我了解如何从函数或SP测试结果返回,但是在就地更新的情况下,如何对照假表和实际表进行测试运行表名是硬编码的吗?我能想到的唯一方法是让整个SP使用动态SQL并将表名作为参数传递,但这会使代码更不易读,更脆弱。有没有更好的办法?下面是一个简单的存储过程,它查看另外两个字段:TransactionDate和ENdOfDropDate,并在同一个表中设置第三个字段,名为" IsWithinAddDrop"根据条件的结果判断为真还是假。

create table  tblT1
(
   ID [bigint] IDENTITY(1,1) NOT NULL,
   TransactionDate   [datetime2](7) NULL,
   EndOfDropDate      [datetime2](7) NULL, 
   IsWithinAddDrop [nvarchar](10) NULL
)

insert into tblT1 (TransactionDate, EndOfDropDate) values ('1/1/2016',  '2/1/2016')
insert into tblT1 (TransactionDate, EndOfDropDate) values ('2/1/2016',  '1/2/2016')
insert into tblT1 (TransactionDate, EndOfDropDate) values ('3/1/2016',  '3/1/2016')

create procedure spUpdateIsWithinAddDrop
as 
begin
    Update t1
        set t1.IsWithinAddDrop =
        (case
            when t1.TransactionDate <= t1.EndOfDropDate then 'True'
            else 'False'
        end)
        from tblT1 t1
end

exec spUpdateIsWithinAddDrop

结果是我要测试的表中更新的列IsWithinAddDrop:

TransactionDate EndOfDropDate   IsWithinAddDrop
2016-01-01      2016-02-01      True
2016-02-01      2016-01-02      False
2016-03-01      2016-03-01      True

谢谢!

1 个答案:

答案 0 :(得分:2)

解决方案是首先模拟表以隔离任何依赖项(外键等)。然后添加足够的数据来测试您想要覆盖的所有案例(请参阅下面的示例中的注释)并使用tSQLt.AssertEqualsTable将目标表的内容与运行下面的过程后的预定义的预期行集进行比较测试


if schema_id(N'StackModuleTests') is null
    exec tSQLt.NewTestClass @ClassName = N'StackModuleTests'
go

if objectpropertyex(object_id(N'[StackModuleTests].[test spUpdateIsWithinAddDrop example]'), N'IsProcedure') = 1
    drop procedure [StackModuleTests].[test spUpdateIsWithinAddDrop example]
go

create procedure [StackModuleTests].[test spUpdateIsWithinAddDrop example]
as
begin
    --! Start by faking the table that will be updated to isolate this test from any other dependencies
    exec tSQLt.FakeTable @TableName = 'dbo.tblT1' ;

    --! We expect spUpdateIsWithinAddDrop to set IsWithinAddDrop to TRUE only if
    --! TransactionDate is less than or equal to EndOfDropDate so we need the
    --! following tests:
    --! 
    --! Positive case where TransactionDate equals EndOfDropDate
    --! Positive case where TransactionDate less than EndOfDropDate
    --! Negative case where TransactionDate more than EndOfDropDate
    --! May want other tests to cover scenarios where either column is null
    --! Purists would say that this should one unit test for each case, personally
    --! I feel that as SQL is a set based language it is OK to combine all cases
    --! into a single test (also minimises all the setup)
    --!

    --! Assemble the data required for all test cases
    insert into tblT1 (TransactionDate, EndOfDropDate)
    values
          ('20160101', '20160101')
        , ('20160101', '20160102')
        , ('20160102', '20160101') ;

    --! What do we expect to see afterwards?
    create table #expected
    (
      TransactionDate [datetime2](7) null
    , EndOfDropDate [datetime2](7) null
    , IsWithinAddDrop [nvarchar](10) null
    )

    insert into #expected (TransactionDate, EndOfDropDate, IsWithinAddDrop)
    values
          ('20160101', '20160101', 'True')
        , ('20160101', '20160102', 'True')
        , ('20160102', '20160101', 'False') ;

    --! Act
    exec dbo.spUpdateIsWithinAddDrop ;

    --! Assert that the contents of tblT1 now match the #expected contents
    --! Notice that we ignore the ID column completely in this test because
    --! it has nothing to do with the object under test (spUpdateIsWithinAddDrop)
    exec tSQLt.AssertEqualsTable @Expected = N'#expected', @Actual = N'tblT1' ;
end
go

exec tSQLt.Run '[StackModuleTests].[test spUpdateIsWithinAddDrop example]';


希望这能充分解释这种方法,但如果没有,请进一步澄清。