当tSQLt faketable不重置表映射时,如何恢复?

zdG*_*eau 10 sql-server tdd tsqlt

faketable功能没有重新分配到正常.我现在使用faketable的所有表都包含我在单元测试插入中使用的值的内容.它是很多表,它使我的数据库无用.请帮助解决这个问题或至少是它的原因.这让我非常担心在CI部署过程中使用它,可能更重要的是在我们的本地开发工作中.

bie*_*ski 6

这只能处理将表放回原位(因为这是 OP 和我都遇到的问题),但是使用放置表的行可能会使其与其他对象类型一起工作。

DECLARE @cmd nvarchar(MAX) = '';

WITH x AS (
    SELECT TOP 10000 
           PL.Id                                            AS Id
          ,PARSENAME(PL.OriginalName,1)                     AS OriginalName
          ,ISNULL(SO.name,'')                               AS name
          ,QUOTENAME(SCHEMA_NAME(ISNULL(SO.schema_id,1)))   AS SchemaName
          ,ISNULL(SEP.major_id,-1)                          AS major_id
      FROM tSQLt.Private_RenamedObjectLog PL
      LEFT JOIN sys.objects SO
        ON ObjectId = object_id
      LEFT JOIN sys.extended_properties SEP
        ON SEP.major_id = SO.object_id
       AND SEP.name = 'tSQLt.FakeTable_OrgTableName'
     ORDER BY SO.create_date DESC
)
SELECT @cmd = @cmd 
       + CASE WHEN x.name = '' OR OriginalName = x.name 
              THEN N'DELETE tSQLt.Private_RenamedObjectLog WHERE Id = ' + CAST(x.Id AS nvarchar) + N';'
              ELSE N'DROP ' 
                 + N'TABLE'   --Replace this with a CASE statement to deal with other object types
                 + N' ' + SchemaName + '.' + QUOTENAME(x.OriginalName) + '; ' 
                 + NCHAR(13) + NCHAR(10) + N'EXEC sp_rename ''' + SchemaName + N'.' 
                                         + QUOTENAME(x.name) + N''',''' + OriginalName + N''';'
                 + NCHAR(13) + NCHAR(10) + N'IF OBJECT_ID('''+SchemaName + N'.' + QUOTENAME(x.name)+N''') IS NULL'
                 + NCHAR(13) + NCHAR(10) + N'BEGIN'
                 + CASE WHEN x.major_id != -1 
                        THEN NCHAR(13) + NCHAR(10) + N'    EXEC sp_dropextendedproperty ''tSQLt.FakeTable_OrgTableName'',''SCHEMA'',''' 
                           + PARSENAME(SchemaName,1) + N''',''TABLE'',''' + OriginalName + N''';'
                        ELSE ''
                   END
                 + NCHAR(13) + NCHAR(10) + N'    DELETE tSQLt.Private_RenamedObjectLog WHERE Id = ' + CAST(x.Id AS nvarchar) + N';'
                 + NCHAR(13) + NCHAR(10) + N'END'
         END
       + NCHAR(13) + NCHAR(10)
       + NCHAR(13) + NCHAR(10)
  FROM x;

--/*   <-Remove leading dashes to execute
PRINT @cmd;
--*/EXEC (@cmd);
Run Code Online (Sandbox Code Playgroud)


den*_*djr 5

您的某个测试或代码可能会使事务处于无法回滚的状态.这通常会导致在结果中看到一个或多个带有"错误"(而不是"成功"或"失败")的测试.

在这些情况下,FakeTable操作不会回滚,并且表处于伪造状态.

在封面下,FakeTable重命名表并创建它的新副本.重命名发生时,操作将记录在tSQLt.Private_RenamedObjectLog中.

例如,您可以使用以下代码重现tSQLt无法正常回滚的错误:

EXEC tSQLt.NewTestClass 'SOF_Example'
GO

CREATE TABLE SOF_Example.MyTable (i INT);
GO

INSERT INTO SOF_Example.MyTable (i) VALUES (5);
GO

CREATE PROCEDURE SOF_Example.[test fake a table]
AS
BEGIN
    EXEC tSQLt.FakeTable 'SOF_Example.MyTable';

    INSERT INTO SOF_Example.MyTable (i) VALUES (12);

    COMMIT;
END;
GO

EXEC tSQLt.Run 'SOF_Example';
Run Code Online (Sandbox Code Playgroud)

您可以使用此代码查看重命名的表日志:

SELECT OriginalName, SCHEMA_NAME(schema_id) + '.' + name AS [Name of Renamed Table], create_date
FROM tSQLt.Private_RenamedObjectLog
JOIN sys.objects ON ObjectId = object_id;
Run Code Online (Sandbox Code Playgroud)

如果您多次重新执行测试,则每个伪造表的日志中可能有许多条目.您可以使用create_date来帮助确定哪个包含原始数据.

现在,尽管如此:最好不要在必须保留数据的数据库中编写和执行测试用例.最好的方法是使用不包含用户数据的数据库(最多只包含基本配置数据).您应该从空白数据库开发和单元测试.填充数据库应该用于其他形式的测试,例如集成,可用性,性能等.

  • Sql Server 允许过程关闭它没有打开的事务。因此,如果被测过程在 tSQLt 打开的事务上执行提交,tSQLt 框架将失去执行这些操作的任何能力。一般来说,在过程中使用事务是一个坏主意。如果必须,请先看看这个:http://sqlity.net/en/585/how-to-rollback-in-procedures/ 所以,不是“工具”中的错误,而是我们必须生活的东西因为我们使用的是 SQL Server。 (2认同)
  • 鉴于问题是已知的,具有如此严重的后果,可以预见到大多数用户都会发生,并且记录重命名是可能的;为什么该工具不包含可以恢复事物的程序?即:读取重命名日志并代表用户反向执行重命名。 (2认同)

Rev*_*eer 5

我对 tSQLt 有同样的问题,并且能够使用表 tSQLt.Private_RenamedObjectLog 的内容恢复所有内容

该表由 tSQLt 框架维护,并证明包含被伪造的原始表的名称,以及临时(即伪造)表的 SQL ObjectID。使用以下查询生成伪造表的列表,以及它们临时重命名的名称(tSQLt 生成的随机名称,例如tSQLt_tempobject_3815e077fea84c7c):

SELECT        
  ObjectId, OriginalName, 
  OBJECT_SCHEMA_NAME(ObjectId) AS SchemaName, 
  OBJECT_NAME(ObjectId) AS TemporaryName
FROM            
  tSQLt.Private_RenamedObjectLog
Run Code Online (Sandbox Code Playgroud)

刷新 SSMS 中的对象资源管理器显示确实存在具有这些随机名称的表,并且它们确实包含我的原始数据(哇!!)。

然后我做了以下事情:

  1. 试了ROLLBACK TRANSACTION一下以防万一。它没有。
  2. 备份数据库(即使它被搞砸了)
  3. 删除假表(即具有原始名称的表,而不是临时名称)
  4. 将表(使用临时名称)重命名回其原始名称,对每个表使用此名称:

    EXEC sp_rename 'schema.tempname', 'originalname'

  5. 在我知道我的表回来后,使用清除了表 tSQLt.Private_RenamedObjectLog

    DELETE FROM tSQLt.Private_RenamedObjectLog

制作一个自动生成恢复脚本的程序会很容易!也许 tSQLt 中已经有一个——有人知道吗?