0

我最近开始通过 Redgate 的 SQL 测试使用 TSQLT 来创建和运行单元测试。我遇到了一个问题。需要超过几分钟才能执行的单元测试将超时,这会停止所有其他单元测试的执行。

如何延长 tSQLt 的超时时间?

我的“单元测试”可能实际上不是单元测试,但我不熟悉另一种更适合的测试方法。

我正在开展一个项目,以提高我们数据仓库的夜间刷新速度。目前,这个过程需要五个小时。通过重新安排任务以尽可能并行运行,我将时间缩短到两个小时。我的问题是,除非我能找到一种方法来证明新流程与旧流程具有完全相同的最终结果,否则 QA 将在接下来的一年中检查每个表中每一行的每一列中的每个值。要么那个,要么这个项目将因为“太难”而被废弃。

所以我想出的测试是这样的:我有一个数据库,在使用我创建的新方法在我们的测试环境中处理结果表之后,我在其中运行一个脚本来复制结果表。然后,回到测试环境,我运行旧进程来更新表。然后,我对每个表运行一个单元测试,以证明使用新方法处理的归档表的内容与使用旧方法重新处理的表的内容完全相同。

不幸的是,由于其中一些表的大小(数百万行),一些单元测试正在超时。以下是我收到的错误:

测试程序:[HR360_unitTest1].[HR360_DW_Job6].[test fact_group_clients Identical Contents] on emr\preprod System.Data.SqlClient.SqlException (0x80131904):超时已过期。在操作完成之前超时时间已过或服务器没有响应。---> System.ComponentModel.Win32Exception (0x80004005):等待操作在 System.Data.SqlClient.SqlConnection.OnError 处超时(SqlException 异常,布尔 breakConnection,Action`1 wrapCloseInAction)在 System.Data.SqlClient.SqlInternalConnection.OnError System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) 在 System.Data.SqlClient.TdsParser 的(SqlException 异常,布尔型 breakConnection,Action`1 wrapCloseInAction)。1 completion, Int32 timeout, Task& task, Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource在 RedGate.SQLTest.tSQLt.FrameworkWrapper.#kz(SqlCommand #LGj) 在 RedGate.SQLTest.tSQLt 的 System.Data.SqlClient.SqlCommand.ExecuteNonQuery() 的 1 完成,字符串 methodName,布尔 sendToPipe,Int32 超时,布尔 asyncWrite)。 FrameworkWrapper.#7qHc(String #2xAd, SqlParameter[] #LvPb) at RedGate.SQLTest.tSQLt.FrameworkWrapper.#qd4b(String #LGxc) at RedGate.SQLTest.tSQLt.TestRunner.Execute(SqlConnection connection) ClientConnectionId:519569ed-03ce -4510-b226-9ff18e0f1d8d 错误号:-2,状态:0,类:11

如果无法增加 tSQLt 的超时时间,那么我将不得不寻找另一种方法来自动测试这些表的内容是否相同(以可随意重复的方式)或放弃该项目。

4

2 回答 2

1

tSQLt 可能不会是我进行此类测试的首选,它是为单元测试而设计的,并且完全适用于单元测试——通常是小部分代码的小型快速测试。你可以看看DbFit之类的东西,但它也会在数据量上遇到困难。

如果您真的必须证明每个表上每一行的每一列都是相同的,我会考虑在两个数据库中的每个表上创建一个 MD5 哈希列,然后只需在每个表中查询哈希不匹配的行。在构建哈希值时,您需要排除任何无法保证在两个表中相同的列,例如 IDENTITY 值、加载日期/时间等。例如:

--! Create our existing table structures create table dbo.ExistingCustomer ( CustomerId int not null identity(1,1) primary key , LastName varchar(50) not null , FirstName varchar(50) not null , MiddleName varchar(50) null , TownOfBirth varchar(50) null , DateOfBirth datetime not null , NumberOfDependents int not null , EtlCreatedOn datetime not null ) go

--! Add a computed column that concatenates all columns of interest --! into a single string, handling NULL's in the process, then creates --! 32 characater MD5 hash over the whole string alter table dbo.ExistingCustomer add DeltaHash as convert(nvarchar(32), hashbytes('MD4' , convert(nvarchar(max) --! Even though you might reasonably expect first and last names ot be populated, --! always code defensively has hashing over a series of empty strings will give --! less confident results , coalesce(nullif(LastName, ''), 'LastName') + coalesce(nullif(FirstName, ''), 'FirstName') --! This pattern is also effective for nullable columns + coalesce(nullif(MiddleName, ''), 'MiddleName') + coalesce(convert(char(24), TownOfBirth, 121), 'TownOfBirth') + coalesce(cast(NumberOfDependents as varchar(32)), 'NumberOfDependents')) collate Latin1_General_CI_AS), 2) persisted go

在构建此哈希时,您需要非常小心排序规则(在两个数据库之间甚至在列级别)和空格。想象一下,您在一行中有四个整数列,所有这些列都是 NULL bar 一列。如果只用空字符串替换 null,则无论第二列或第三列是否包含有效整数,MD5 散列都是相同的。

您需要将此列添加到旧表和新加载数据的副本中,然后您可以使用如下查询:

--! Expect Zero select count(*) as [FailCount] from OldLoadDb.dbo.ExistingCustomer as ec inner join NewLoadDb.dbo.NewCustomer as nc --! This join should probably be on some business key but you get the idea on nc.CustomerId = ec.CustomerId where ec.DeltaHash <> ec.DeltaHash go

像上面这样的东西在 DbFit 中运行得非常好,因为所有繁重的工作都在服务器端完成。

您还应该为存在于一个表中而不存在于另一个表中的行添加测试。

当然,哈希查询不会告诉您有什么区别,但至少可以让您识别不同的行。

于 2017-08-18T07:19:41.477 回答
1

超时问题出现在 Redgate SQL 测试中。因此,长时间运行的单元测试的简单解决方案是通过调用 tSQLt.Run 直接在 tSQLt 框架中运行它们。在我的测试中,tSQLt 似乎没有超时问题。在撰写本文时,我有一个单元测试已经连续运行了 19 个小时而没有超时。

这个单元测试需要很长时间才能运行,在我的特殊情况下会产生它自己的问题。我将使用散列解决方案或 EXCEPT 解决方案来解决此问题,如@datacentricity 的响应中所讨论的线程。

于 2017-08-23T16:22:07.833 回答