Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 使用TSQLT FakeTable测试存储过程创建的表_Sql Server_Unit Testing_Tsqlt - Fatal编程技术网

Sql server 使用TSQLT FakeTable测试存储过程创建的表

Sql server 使用TSQLT FakeTable测试存储过程创建的表,sql-server,unit-testing,tsqlt,Sql Server,Unit Testing,Tsqlt,我正在学习为工作编写单元测试。有人建议我使用TSQLT FakeTable测试存储过程创建的表的某些方面 在其他单元测试中,我们为存储过程创建一个临时表,然后测试临时表。我不知道如何把伪造的东西运用到测试中 EXEC tSQLt.NewTestClass 'TestThing'; GO CREATE OR ALTER PROCEDURE TestThing.[test API_StoredProc

我正在学习为工作编写单元测试。有人建议我使用TSQLT FakeTable测试存储过程创建的表的某些方面

在其他单元测试中,我们为存储过程创建一个临时表,然后测试临时表。我不知道如何把伪造的东西运用到测试中

EXEC tSQLt.NewTestClass 'TestThing'; 
GO                                                 
CREATE OR ALTER PROCEDURE TestThing.[test API_StoredProc to make sure parameters work] 
AS 
BEGIN
    DROP TABLE IF EXISTS #Actual;
    CREATE TABLE #Actual   ----Do I need to create the temp table and the Fake table? I thought I  might need to because I'm testing a table created by a stored procedure.
    ( 
        ISO_3166_Alpha2 NVARCHAR(5),
        ISO_3166_Alpha3 NVARCHAR(5),
        CountryName NVARCHAR(100),
        OfficialStateName NVARCHAR(300),
        sovereigny NVARCHAR(75),
        icon NVARCHAR(100)
    );
    INSERT #Actual
    (
        ISO_3166_Alpha2,
        ISO_3166_Alpha3,
        CountryName,
        OfficialStateName,
        sovereigny,
        icon
    )


    EXEC Marketing.API_StoredProc @Username = 'AnyValue',                              -- varchar(100)
                                                 @FundId = 0,                                 -- int
                                                 @IncludeSalesForceInvestorCountry = NULL,    -- bit
                                                 @IncludeRegisteredSalesJurisdictions = NULL, -- bit
                                                 @IncludeALLCountryForSSRS = NULL,            -- bit
                                                 @WHATIF = NULL,                              -- bit
                                                 @OUTPUT_DEBUG = NULL                         -- bit


   EXEC tsqlt.FakeTable @TableName = N'#Actual',        -- nvarchar(max)  -- How do I differentiate between the faketable and the temp table now? 
                        @SchemaName = N'',       -- nvarchar(max)
                        @Identity = NULL,        -- bit
                        @ComputedColumns = NULL, -- bit
                        @Defaults = NULL         -- bit

  INSERT INTO #Actual 
  (
        ISO_3166_Alpha2,
        ISO_3166_Alpha3,
        CountryName,
        OfficialStateName,
        sovereigny,
        icon
    )
    VALUES 
      ('AF', 'AFG', 'Afghanistan', 'The Islamic Republic of Afghanistan', 'UN MEMBER STATE', 'test')

SELECT * FROM #actual 

END;
GO
EXEC tSQLt.Run 'TestThing';
我试图用上面的代码做的基本上就是让FakeTable工作。我得到一个错误:FakeTable could无法解析实际的对象名


我最终想要测试的是存储过程中的参数。如果IncludeSalesForceInvestorCountry设置为1,则只应返回某些条目。应该返回的内容可能会随着时间的推移而改变,因此建议我使用FakeTable

在您的场景中,您不需要伪造任何临时表,只需伪造Marketing.API_StoredProc引用的表,并用期望返回的值填充它,有些则不需要。添加您希望在预期表中看到的内容,调用Marketing.API_StoredProc将结果转储到实际表中,并将结果与tSQLt.AssertEqualsTable进行比较

一个好的起点可能是回顾tSQLT.FakeTable的工作原理和一个真实的用例

正如您所知,每个单元测试都在tSQLT框架启动和回滚的自己的事务中运行。在单元测试中调用tSQLt.FakeTable时,它会临时重命名指定的表,然后创建该表的精确命名的传真。临时副本允许每列为NULL,没有主键或外键、标识列、检查、默认或唯一约束,尽管其中一些约束可以包含在传真表中,具体取决于传递给tSQLt.FakeTable的参数。在测试事务期间,任何引用名称表的对象都将使用假表而不是真表。测试结束时,tSQLt回滚事务,删除假表,并将原始表返回到其以前的状态。所有这些都会自动发生。你可能会问,这有什么意义

假设您有一个[OrderDetail]表,其中的列包括OrderId和ProductId作为主键,一个OrderStatusId列加上一组其他非空列。此表的DDL可能如下所示

CREATE TABLE [dbo].[OrderDetail]
(
  OrderDetailId int IDENTITY(1,1) NOT NULL
, OrderId int NOT NULL
, ProductId int NOT NULL
, OrderStatusId int NOT NULL
, Quantity int NOT NULL
, CostPrice decimal(18,4) NOT NULL
, Discount decimal(6,4) NOT NULL
, DeliveryPreferenceId int NOT NULL
, PromisedDeliveryDate datetime NOT NULL
, DespatchDate datetime NULL
, ActualDeliveryDate datetime NULL
, DeliveryDelayReason varchar(500) NOT NULL
/* ... other NULL and NOT NULL columns */
, CONSTRAINT PK_OrderDetail PRIMARY KEY CLUSTERED (OrderId, ProductId)
, CONSTRAINT AK_OrderDetail_AutoIncrementingId UNIQUE NONCLUSTERED (OrderDetailId)
, CONSTRAINT FK_OrderDetail_Order FOREIGN KEY (OrderId) REFERENCES [dbo].[Orders] (OrderId)
, CONSTRAINT FK_OrderDetail_Product FOREIGN KEY (ProductId) REFERENCES [dbo].[Product] (ProductId)
, CONSTRAINT FK_OrderDetail_OrderStatus FOREIGN KEY (OrderStatusId) REFERENCES [dbo].[OrderStatus] (OrderStatusId)
, CONSTRAINT FK_OrderDetail_DeliveryPreference FOREIGN KEY (DeliveryPreferenceId) REFERENCES [dbo].[DeliveryPreference] (DeliveryPreferenceId)
);
如您所见,此表对Orders、Product、DeliveryPreference和OrderStatus表具有外键依赖关系。反过来,产品可能具有引用ProductType、BrandCategory、Supplier等的外键。Orders表包含对Customer、Address和SalesPerson等的外键引用。此链中的所有表都有许多列定义为NOTNULL和/或受CHECK和其他约束约束。其中一些表本身有更多的外键

现在,假设您想编写一个存储过程OrderDetailStatusUpdate,其任务是更新OrderDetail表中单个行的订单状态。它有三个输入参数@OrderId、@ProductId和@OrderStatusId。考虑一下您需要做些什么来设置此过程的测试。您需要向OrderDetail表中添加至少两行,包括所有非空列。您还需要将父记录添加到所有FK引用的表,以及层次结构中该表之上的任何表,以确保所有插入也符合这些表上的所有可空性和其他约束。据我统计,至少有11个表需要填充,全部用于一个简单的测试。即使您咬紧牙关,进行所有这些设置,在将来的某个时候,可能会有人出现,向其中一个表中添加一个新的NOTNULL列,或者更改一个会导致测试失败的约束,而该失败实际上与您的测试或您正在测试的存储过程无关。测试驱动开发的一个基本原则是,一个测试应该只有失败的理由,我数了几十个

tSQLT.FakeTable用于救援

为该程序设置测试,您实际需要做的最低限度是什么?您需要两个行到OrrimeDebug表中,其中一个得到更新,一个不需要,并且您实际上需要考虑的唯一列是OrdID和PosiTID,即标识键加OrraseStasud -列正在更新。其余立柱虽然在整体设计中很重要,但与测试对象无关。在OrderDetailStatusUpdate测试中,您将遵循以下步骤:

调用tSQLt.FakeTable'dbo.OrderDetail' 使用OrderId、ProductId和OrderStatusId创建所需的表 列,并用两行填充它 一个将具有预期的OrderStatusId,另一个可以为空 将两行添加到现在模拟的OrderDetail表OrderId和 仅ProductId 调用程序unde r测试OrderDetailStatusUpdate通过 插入的行之一的OrderID和ProductID以及 您正在更改为的OrderStatusId。 使用tSQLt.AssertEqualsTable将预期表与 OrderDetail表。此断言将仅比较上的列 对于预期的表,将忽略OrderDetail上的其他列 创建此测试非常快,而且它可能失败的唯一原因是,与被测代码相关的某些内容在底层模式中发生了更改。对OrderDetail表或任何父/父表上的任何其他列的更改不会导致此测试中断


因此,使用tSQLt.FakeTable或任何其他类型的模拟对象的原因是为了提供真正强大的测试隔离和简单的测试数据准备。

在您的场景中,您不需要伪造任何临时表,只需伪造Marketing.API\u StoredProc引用的表,并用期望返回的值填充它即可,有些你不知道。添加您希望在预期表中看到的内容,调用Marketing.API_StoredProc将结果转储到实际表中,并将结果与tSQLt.AssertEqualsTable进行比较

一个好的起点可能是回顾tSQLT.FakeTable的工作原理和一个真实的用例

正如您所知,每个单元测试都在tSQLT框架启动和回滚的自己的事务中运行。在单元测试中调用tSQLt.FakeTable时,它会临时重命名指定的表,然后创建该表的精确命名的传真。临时副本允许每列为NULL,没有主键或外键、标识列、检查、默认或唯一约束,尽管其中一些约束可以包含在传真表中,具体取决于传递给tSQLt.FakeTable的参数。在测试事务期间,任何引用名称表的对象都将使用假表而不是真表。测试结束时,tSQLt回滚事务,删除假表,并将原始表返回到其以前的状态。所有这些都会自动发生。你可能会问,这有什么意义

假设您有一个[OrderDetail]表,其中的列包括OrderId和ProductId作为主键,一个OrderStatusId列加上一组其他非空列。此表的DDL可能如下所示

CREATE TABLE [dbo].[OrderDetail]
(
  OrderDetailId int IDENTITY(1,1) NOT NULL
, OrderId int NOT NULL
, ProductId int NOT NULL
, OrderStatusId int NOT NULL
, Quantity int NOT NULL
, CostPrice decimal(18,4) NOT NULL
, Discount decimal(6,4) NOT NULL
, DeliveryPreferenceId int NOT NULL
, PromisedDeliveryDate datetime NOT NULL
, DespatchDate datetime NULL
, ActualDeliveryDate datetime NULL
, DeliveryDelayReason varchar(500) NOT NULL
/* ... other NULL and NOT NULL columns */
, CONSTRAINT PK_OrderDetail PRIMARY KEY CLUSTERED (OrderId, ProductId)
, CONSTRAINT AK_OrderDetail_AutoIncrementingId UNIQUE NONCLUSTERED (OrderDetailId)
, CONSTRAINT FK_OrderDetail_Order FOREIGN KEY (OrderId) REFERENCES [dbo].[Orders] (OrderId)
, CONSTRAINT FK_OrderDetail_Product FOREIGN KEY (ProductId) REFERENCES [dbo].[Product] (ProductId)
, CONSTRAINT FK_OrderDetail_OrderStatus FOREIGN KEY (OrderStatusId) REFERENCES [dbo].[OrderStatus] (OrderStatusId)
, CONSTRAINT FK_OrderDetail_DeliveryPreference FOREIGN KEY (DeliveryPreferenceId) REFERENCES [dbo].[DeliveryPreference] (DeliveryPreferenceId)
);
如您所见,此表对Orders、Product、DeliveryPreference和OrderStatus表具有外键依赖关系。反过来,产品可能具有引用ProductType、BrandCategory、Supplier等的外键。Orders表包含对Customer、Address和SalesPerson等的外键引用。此链中的所有表都有许多列定义为NOTNULL和/或受CHECK和其他约束约束。其中一些表本身有更多的外键

现在,假设您想编写一个存储过程OrderDetailStatusUpdate,其任务是更新OrderDetail表中单个行的订单状态。它有三个输入参数@OrderId、@ProductId和@OrderStatusId。考虑一下您需要做些什么来设置此过程的测试。您需要向OrderDetail表中添加至少两行,包括所有非空列。您还需要将父记录添加到所有FK引用的表,以及层次结构中该表之上的任何表,以确保所有插入也符合这些表上的所有可空性和其他约束。据我统计,至少有11个表需要填充,全部用于一个简单的测试。即使您咬紧牙关,进行所有这些设置,在将来的某个时候,可能会有人出现,向其中一个表中添加一个新的NOTNULL列,或者更改一个会导致测试失败的约束,而该失败实际上与您的测试或您正在测试的存储过程无关。测试驱动开发的一个基本原则是,一个测试应该只有失败的理由,我数了几十个

tSQLT.FakeTable用于救援

为该程序设置测试,您实际需要做的最低限度是什么?您需要两个行到OrrimeDebug表中,其中一个得到更新,一个不需要,并且您实际上需要考虑的唯一列是OrdID和PosiTID,即标识键加OrraseStasud -列正在更新。其余立柱虽然在整体设计中很重要,但与测试对象无关。在OrderDetailStatusUpdate测试中,您将遵循以下步骤:

调用tSQLt.FakeTable'dbo.OrderDetail' 使用OrderId、ProductId和OrderStatusId创建所需的表 列,并用两行填充它 一个将具有预期的OrderStatusId,另一个可以为空 将两行添加到现在模拟的OrderDetail表OrderId和 仅ProductId 调用程序unde r测试OrderDetailStatusUpdate通过 插入的行之一的OrderID和ProductID以及 您正在更改为的OrderStatusId。 使用tSQLt.AssertEqualsTable将预期表与 OrderDetail表。此断言将仅比较上的列 对于预期的表,将忽略OrderDetail上的其他列 创建此测试非常快,而且它可能失败的唯一原因是,与被测代码相关的某些内容在底层模式中发生了更改。对OrderDetail表或任何父/父表上的任何其他列的更改不会导致此测试中断


因此,使用tSQLt.FakeTable或任何其他类型的模拟对象的原因是为了提供真正健壮的测试隔离和简单的测试数据准备。

根据文档,FakeTable不能与名称以或开头的临时表一起使用。参考:根据文档,FakeTable不能与名称以或开头的临时表一起使用。非常感谢你花时间写了这么详细的解释,有没有什么方法可以在不创建其他帐户的情况下两次更新这个答案谢谢你,你的评论是肯定的。非常感谢你花时间写了这么详细的解释。有什么方法可以在不创建另一个帐户的情况下两次更新这个答案谢谢,你的评论已经足够了