如何对tSQLt中的伪造表应用索引
使用针对MS SQL Server(2012)的优秀测试框架(v1.0.5137.39257),我尝试构建一个测试,以检查唯一索引是否有效,并在插入重复值时生成异常 经过广泛的搜索,我找不到一种方法将索引应用于伪造的表(内置tSQLt proc或额外代码)。需要类似于如何对tSQLt中的伪造表应用索引,sql,sql-server,unit-testing,tsqlt,Sql,Sql Server,Unit Testing,Tsqlt,使用针对MS SQL Server(2012)的优秀测试框架(v1.0.5137.39257),我尝试构建一个测试,以检查唯一索引是否有效,并在插入重复值时生成异常 经过广泛的搜索,我找不到一种方法将索引应用于伪造的表(内置tSQLt proc或额外代码)。需要类似于tSQLt.ApplyIndex的东西。有人做到了吗 另一种可能是分叉tSQLt代码,并基于处的代码添加一个proc,以便在伪造的表上重新创建索引。然而,这将是相当多的工作 测试条件(假设已在数据库中安装): 创建测试类,测试并运行
tSQLt.ApplyIndex
的东西。有人做到了吗
另一种可能是分叉tSQLt代码,并基于处的代码添加一个proc,以便在伪造的表上重新创建索引。然而,这将是相当多的工作
测试条件(假设已在数据库中安装):
创建测试类,测试并运行它(当然会失败,因为过程调用ApplyIndex不存在):
当然,如果索引不起作用,上述测试就会失败
清理:
DROP PROCEDURE tests.[test that inserting a duplicate value in tblTestUniqueIndex raises an error]
GO
EXEC tSQLt.DropClass 'tests'
GO
DROP TABLE dbo.tblTestUniqueIndex
GO
谢谢首先,我必须承认我喜欢你在例子中选择的城市。我不明白你为什么在这个例子中使用FakeTable。为什么不在没有FakeTable的情况下编写测试并针对真实表进行测试呢。有些情况下,这可能有点痛苦。i、 如果您有一个包含许多必填字段的表,但实际上可能有更好的方法来编写您想要的测试。如果您通过插入重复的行来检查唯一约束或主键,我建议您测试SQL Server本身的功能是否按预期工作。如果我要编写测试,我会通过查询信息模式或sys表来测试约束的存在。首先,我必须承认我喜欢您在示例中选择的城市。我不明白你为什么在这个例子中使用FakeTable。为什么不在没有FakeTable的情况下编写测试并针对真实表进行测试呢。有些情况下,这可能有点痛苦。i、 如果您有一个包含许多必填字段的表,但实际上可能有更好的方法来编写您想要的测试。如果您通过插入重复的行来检查唯一约束或主键,我建议您测试SQL Server本身的功能是否按预期工作。如果要编写测试,我将通过查询信息\u schema或sys表来测试约束的存在。您不能创建唯一约束吗?您仍然可以在引擎盖下获得所需的索引。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
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
创建新的测试类(假定已安装最新版本1.0.5325.27056)
第一个测试确认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
也被约束为使用唯一约束唯一
-- 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
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引用,以此类推。没有简单的方法来处理这个问题,但是我已经实现了测试数据生成器模式的一个版本。这背后的思想是为每个实体创建一个存储过程,该过程自动处理这些依赖关系(即向父表和父表添加任何必要的行)。通常,在创建了所有依赖项之后,TDB存储过程会将生成的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
几年前,我写了一篇关于使用for SQL的博客文章。我希望这有助于解释我的想法。您不能创建一个唯一的约束吗?您仍然可以在引擎盖下获得所需的索引。ApplyConstraint对唯一键的作用与对主键的作用相同,但仅适用于最新版本的IIRC。例如:
CREATE TABLE TestTable (
FirstName VARCHAR(255),
LastName VARCHAR (255),
Gender VARCHAR (255),
Age INT
);
INSERT INTO TestTable (FirstName, LastName, Gender, Age) VALUES ('Tapos','Noor','Female',21);
ALTER TABLE TestTable ADD CONSTRAINT My_Constraint UNIQUE (FirstName);
EXEC tSQLt.FakeTable @TableName = 'TestTable';
EXEC tSQLt.ApplyConstraint @TableName = 'TestTable', @ConstraintName = 'My_Constraint';
INSERT INTO TestTable (FirstName, LastName, Gender, Age) VALUES ('Tapos', 'Noor', 'Male',24);
EXEC tSQLt.ExpectException @ExpectedErrorNumber = 2627
, @ExpectedMessagePattern = 'Violation of UNIQUE KEY constraint%';
INSERT INTO TestTable (FirstName, LastName, Gender, Age) VALUES ('Narullah', 'Noor', 'Male',24);
从上面创建的表的类似版本开始,为每种类型的唯一约束提供足够的列
-- 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
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
创建新的测试类(假定已安装最新版本1.0.5325.27056)
第一个测试确认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
也被约束为使用唯一约束唯一
-- 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
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引用,以此类推。没有简单的方法来处理这个问题,但是我已经实现了测试数据生成器模式的一个版本。这背后的思想是为每个实体创建一个存储过程,该过程自动处理这些依赖关系(即向父级和gra添加任何必要的行)