如何使用 tSQLt 测试更新 table(相对于返回结果集)的 SQL 存储过程
How to test a TSQL stored procedure that updates a table (vs. returning a result set) using tSQLt
SQL专家能否插话一下测试一种存储过程的方法,这种存储过程什么都不 return,但在 table 中执行字段更新?我了解如何从函数或 SP 测试结果 returned,但是如果是就地更新,我该如何进行测试 运行假 table 与实际的 table 如果程序具有硬编码的 table 名称?我能想到的唯一方法是让整个SP使用动态SQL并将table名称作为参数传递,但这样会使代码的可读性更差且更脆弱。有没有更好的办法?下面是一个简单的存储过程,它查看另外两个字段:TransactionDate 和 EndOfDropDate,并根据条件的结果将同一 table 中名为 "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
结果是我要测试的 table 中的更新列 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
谢谢!
解决方案是首先模拟 table 以隔离任何依赖项(外键等)。然后添加足够的数据来测试您想要涵盖的所有情况(请参阅下面示例中的注释)并使用 tSQLt.AssertEqualsTable
将目标 table 的内容与之后的一组预定义的预期行进行比较运行 正在测试的程序。
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]';
希望这足以解释该方法,但如果没有,请寻求进一步的说明。
SQL专家能否插话一下测试一种存储过程的方法,这种存储过程什么都不 return,但在 table 中执行字段更新?我了解如何从函数或 SP 测试结果 returned,但是如果是就地更新,我该如何进行测试 运行假 table 与实际的 table 如果程序具有硬编码的 table 名称?我能想到的唯一方法是让整个SP使用动态SQL并将table名称作为参数传递,但这样会使代码的可读性更差且更脆弱。有没有更好的办法?下面是一个简单的存储过程,它查看另外两个字段:TransactionDate 和 EndOfDropDate,并根据条件的结果将同一 table 中名为 "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
结果是我要测试的 table 中的更新列 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
谢谢!
解决方案是首先模拟 table 以隔离任何依赖项(外键等)。然后添加足够的数据来测试您想要涵盖的所有情况(请参阅下面示例中的注释)并使用 tSQLt.AssertEqualsTable
将目标 table 的内容与之后的一组预定义的预期行进行比较运行 正在测试的程序。
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]';
希望这足以解释该方法,但如果没有,请寻求进一步的说明。