难道你不能创建一个唯一的约束吗?你仍然可以得到所需的索引。 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
是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引用其他表的外键引用。有没有简单的方法来处理这个问题,但我已经实现了Test Data Builder模式的一个版本。这背后的想法是每个实体自动处理这些依赖关系的存储过程(即向父级表父母&添加任何必要的行)。通常,创建所有依赖项后,TDB sproc会将生成的ID用作输出参数,以便可以重用这些值。
所以,如果我用的是测试数据生成器模式,我的测试可能是这样的:
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
我写了一对夫妇几年前使用Test Data Builder pattern用于SQL博客文章。我希望这有助于解释我的想法。
我承认我没有使用TSQLT,但正在验证一个唯一索引可以防止重复条目真的是一个有效的测试吗?如果它不起作用,你会做什么改变?似乎框架功能不在单元测试的范围内。 –
你可以应用约束吗? – Andrew
因此索引可以被禁用,或者唯一性可以通过一些其他手段来强制执行。在我们将模式同步到生产服务器之前,单元测试需要验证,无论如何,插入重复值都会引发错误。 – DaveBoltman