你不能创建一个唯一的约束吗?您仍然会在后台获得所需的索引。tSQLt.ApplyConstraint 对唯一键的作用与对主键的作用相同——但仅在最新版本的 IIRC 中。例如:
从您在上面创建的表的类似版本开始,为每种类型的唯一约束提供足够的列
-- Create a sample table with a UNIQUE INDEX
set ansi_nulls, quoted_identifier, ansi_padding on
go
if object_id('dbo.StackTable') is not null
drop table dbo.StackTable;
create table dbo.StackTable
(
Id int not null identity(1, 1)
, UniqueKeyColumn varchar(50) null
, UniqueIndexColumn int null
);
go
if object_id('PK_StackTable') is null
alter table dbo.StackTable add constraint [PK_StackTable]
primary key clustered (Id);
go
if object_id('AK_StackTable_UniqueKeyColumn') is null
alter table dbo.StackTable add constraint [AK_StackTable_UniqueKeyColumn]
unique nonclustered (UniqueKeyColumn);
go
if object_id('NCI_StackTable_UniqueIndexColumn') is null
create unique nonclustered index [NCI_StackTable_UniqueIndexColumn]
on dbo.StackTable (UniqueIndexColumn);
go
新建一个测试类(假设已经安装了最新版本1.0.5325.27056)
if schema_id('StackTableTests') is null
exec tSQLt.NewTestClass @ClassName = 'StackTableTests';
go
第一个测试确认 Id 被限制为唯一并且该约束是主键
if object_id('[StackTableTests].[test id is unique]') is not null
drop procedure [StackTableTests].[test id is unique];
go
create procedure [StackTableTests].[test id is unique]
as
begin
exec tSQLt.FakeTable @TableName = 'dbo.StackTable';
exec tSQLt.ApplyConstraint @TableName = 'dbo.StackTable', @ConstraintName = 'PK_StackTable';
--! Add the row we're going to duplicate
insert dbo.StackTable (Id) values (-999);
--! If we insert the same value again, we should expect to see an exception
exec tSQLt.ExpectException @ExpectedErrorNumber = 2627
, @ExpectedMessagePattern = 'Violation of PRIMARY KEY constraint%';
insert dbo.StackTable (Id) values (-999);
end
go
下一个测试还使用唯一约束ApplyConstraint
来确认也被约束为唯一UniqueKeyColumn
if object_id('[StackTableTests].[test UniqueKeyColumn is unique]') is not null
drop procedure [StackTableTests].[test UniqueKeyColumn is unique];
go
create procedure [StackTableTests].[test UniqueKeyColumn is unique]
as
begin
exec tSQLt.FakeTable @TableName = 'dbo.StackTable';
exec tSQLt.ApplyConstraint
@TableName = 'dbo.StackTable', @ConstraintName = 'AK_StackTable_UniqueKeyColumn';
--! Add the row we're going to duplicate
insert dbo.StackTable (UniqueKeyColumn) values ('Oops!');
--! If we insert the same value again, we should expect to see an exception
exec tSQLt.ExpectException @ExpectedErrorNumber = 2627
, @ExpectedMessagePattern = 'Violation of UNIQUE KEY constraint%';
insert dbo.StackTable (UniqueKeyColumn) values ('Oops!');
end
go
目前,测试唯一索引的唯一方法是针对真实的、非伪造的表。在这个例子中,UniqueKeyColumn
是 a varchar(50)
,因为这是真正的表,它可能已经包含数据。所以我们需要能够指定两个唯一的值,这样我们的测试就不会破坏错误的约束。最简单的方法是使用几个 GUID。
if object_id('[StackTableTests].[test UniqueIndexColumn is unique]') is not null
drop procedure [StackTableTests].[test UniqueIndexColumn is unique];
go
create procedure [StackTableTests].[test UniqueIndexColumn is unique]
as
begin
--! Have to use the real table here as we can't use ApplyConstraint on a unique index
declare @FirstUniqueString varchar(50) = cast(newid() as varchar(50));
declare @NextUniqueString varchar(50) = cast(newid() as varchar(50));
--! Add the row we're going to duplicate
insert dbo.StackTable (UniqueKeyColumn, UniqueIndexColumn) values (@FirstUniqueString, -999);
--! If we insert the same value again, we should expect to see an exception
exec tSQLt.ExpectException @ExpectedErrorNumber = 2601
, @ExpectedMessagePattern = 'Cannot insert duplicate key row in object ''dbo.StackTable'' with unique index%';
insert dbo.StackTable (UniqueKeyColumn, UniqueIndexColumn) values (@NextUniqueString, -999);
end
go
exec tSQLt.Run '[StackTableTests]';
go
针对真实表进行测试的潜在问题是它可能具有对其他表的外键引用,而这些外键引用又可能对其他表具有其他 FK 引用等等。没有简单的方法可以解决这个问题,但我已经实现了测试数据构建器模式的一个版本。这背后的想法是每个实体的存储过程,它自动处理这些依赖关系(即向父表和祖父表添加任何必要的行)。通常,在创建了所有依赖项后,TDB 存储过程将使生成的 ID 可用作输出参数,以便可以重用这些值。
因此,如果我使用 Test Data Builder 模式,我的测试可能如下所示:
create procedure [StackTableTests].[test UniqueIndexColumn is unique]
as
begin
--! Have to use the real table here as we can't use ApplyConstraint on a unique index
declare @FirstUniqueString varchar(50) = cast(newid() as varchar(50));
declare @NextUniqueString varchar(50) = cast(newid() as varchar(50));
declare @NewId int;
--! Add the row we're going to duplicate
-- The TDB should output the ID's of any FK references so they
--! can be reused on the next insert
exec TestDataBuilders.StackTableBuilder
@UniqueKeyColumn = @FirstUniqueString
, @UniqueIndexColumn = -999
--! If we insert the same value again, we should expect to see an exception
exec tSQLt.ExpectException @ExpectedErrorNumber = 2601
, @ExpectedMessagePattern = 'Cannot insert duplicate key row in object ''dbo.StackTable'' with unique index%';
insert dbo.StackTable (UniqueKeyColumn, UniqueIndexColumn) values (@NextUniqueString, -999);
end
go
exec tSQLt.Run '[StackTableTests]';
go
几年前,我写了一篇关于使用SQL测试数据构建器模式的博客文章。我希望这有助于解释我的想法。