当我在由AG组上的DTC_SUPPORT = PER_DB配置的Always On可用性组中设置的SQL Server 2017上运行tSQLt测试时收到以下错误。如果我关闭了DTC支持,它可以正常工作。我们的环境需要DTC。是否可以在tSQLt中解决此问题,或者是否可以通过其他方式配置SQL,以便DTC和tSQLt都能正常工作?
这是错误:
Test Procedure: [xxx].[zzfnCipValidateCustomerAddress].[test '12345' Zip Codes] on DbServer
[zzfnCipValidateCustomerAddress].[test '12345' Zip Codes] failed: (Error) Cannot promote the transaction to a distributed transaction because there is an active save point in this transaction.[16,1]{zzfnCipValidateCustomerAddress.test '12345' Zip Codes,36} (There was also a ROLLBACK ERROR --> The current transaction cannot be committed and cannot be rolled back to a savepoint. Roll back the entire transaction.{tSQLt.Private_RunTest,160})
这是失败的测试之一:
CREATE PROCEDURE [zzfnCipValidateCustomerAddress].[test '12345' Zip Codes]
AS
BEGIN
--Assemble
/*
Test to determine if function is an Inline Table Valued function or not
since this function is being rewritten to be an ITVF function and this test should
pass both versions
*/
DECLARE @IsITVF BIT;
SELECT @IsITVF = IIF(fc.FunctionCount > 0, 1, 0)
FROM
(
SELECT COUNT(*) AS FunctionCount
FROM sys.sql_modules AS sm
JOIN sys.objects AS o
ON sm.object_id = o.object_id
WHERE sm.object_id = OBJECT_ID('dbo.fnCipValidateCustomerAddress')
AND o.type = 'IF' --'IF' = Inline Valued Table Function
) AS fc;
SELECT @IsITVF;
--DROP TABLE IF EXISTS zzfnCipValidateCustomerAddress.TestData;
CREATE TABLE zzfnCipValidateCustomerAddress.TestData
(
AddressLine1 VARCHAR(100),
AddressLine2 VARCHAR(100),
City VARCHAR(50),
StateAbbr VARCHAR(3),
ZipCode VARCHAR(9)
);
INSERT INTO zzfnCipValidateCustomerAddress.TestData
(
AddressLine1,
AddressLine2,
City,
StateAbbr,
ZipCode
)
VALUES
('Test', NULL, 'Test', 'AZ', '12345');
CREATE TABLE zzfnCipValidateCustomerAddress.Expected
(
AddressLine1 VARCHAR(100),
AddressLine2 VARCHAR(100),
City VARCHAR(50),
StateAbbr VARCHAR(3),
ZipCode VARCHAR(9),
CipExceptionReasonId INT
);
INSERT INTO zzfnCipValidateCustomerAddress.Expected
(
AddressLine1,
AddressLine2,
City,
StateAbbr,
ZipCode,
CipExceptionReasonId
)
VALUES
('Test', NULL, 'Test', 'AZ', '12345', 8);
--Act
IF (@IsITVF = 0)
BEGIN
SELECT td.AddressLine1,
td.AddressLine2,
td.City,
td.StateAbbr,
td.ZipCode,
dbo.fnCipValidateCustomerAddress(td.AddressLine1, td.AddressLine2, td.City, td.StateAbbr, td.ZipCode) AS CipExceptionReasonId
INTO zzfnCipValidateCustomerAddress.Actual
FROM zzfnCipValidateCustomerAddress.TestData AS td;
END;
ELSE
BEGIN
SELECT fcvcat.AddressLine1,
fcvcat.AddressLine2,
fcvcat.City,
fcvcat.StateAbbr,
fcvcat.ZipCode,
fcvcat.CipExceptionReasonId
INTO zzfnCipValidateCustomerAddress.Actual
FROM zzfnCipValidateCustomerAddress.TestData AS td
CROSS APPLY dbo.fnCipValidateCustomerAddress(
td.AddressLine1,
td.AddressLine2,
td.City,
td.StateAbbr,
td.ZipCode
) AS fcvcat;
END;
--Assert
EXEC tSQLt.AssertEqualsTable @Expected = N'zzfnCipValidateCustomerAddress.Expected',
@Actual = N'zzfnCipValidateCustomerAddress.Actual',
@Message = N'',
@FailMsg = N'Zip with value of ''12345'' did not generate a CipExceptionReasonId as expected';
END;
答案 0 :(得分:2)
tSQLt在内部依赖事务保存点。保存点与分布式事务不兼容。
tSQLt当前无法更改事务处理。
我的建议是设置一个专用于执行自动测试套件的CI(连续集成)环境(因此不需要启用AlwaysOn)。不管您的具体情况如何,这都是业界最佳做法。
但是,这不能解决专门用于AlwaysOn设置的测试过程。您自然必须在启用AlwaysOn的环境中进行测试。在这种情况下,您可以使用tSQLt.NewConnection
命令,该命令执行在单独的连接上以及在tSQLt事务之外的连接上传入的命令。
但是请记住,在这种情况下,您将负责所有清理操作,因为通过tSQLt.NewConnection
执行的任何操作显然不会被tSQLt回滚。