2

tSQLt 专家能否介绍测试一种不返回任何内容但在表中执行字段更新的存储过程的方法?我了解如何测试从函数或 SP返回的结果,但是在就地更新的情况下,如果过程具有硬编码的表名,我如何使测试针对假表与实际表运行? 我能想到的唯一办法就是让整个SP使用动态SQL,并把表名作为参数传进去,但是这样会让代码的可读性降低,更脆。有没有更好的办法?下面是一个简单的存储过程,它查看 2 个其他字段:TransactionDate 和 ENdOfDropDate,并根据条件的结果将同一个表中名为“IsWithinAddDrop”的第三个字段设置为 True 或 False。

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

谢谢!

4

1 回答 1

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]';


希望这充分解释了该方法,但如果没有,请寻求进一步澄清。

于 2016-03-16T09:28:02.693 回答