在包含 TRY/CATCH 的测试过程中使用 tSQLt AssertEqualsTableSchema
Using tSQLt AssertEqualsTableSchema in a test procedure that contains TRY/CATCH
似乎 SQL 测试框架 tSQLt 不允许在生成错误的 TRY/CATCH 块之后使用诸如 tSQLt.AssertEqualsTableSchema 的断言。如果我尝试这样做,测试会生成错误而不是 pass/fail 结果。另一方面,更简单的断言如 tSQLt.AssertEquals 在这种情况下有效,通过了测试。
我想知道在这种情况下是否有办法使用这样的断言语句,或者它是否是 tSQLt 的基本限制并且它不起作用。
此代码重现了问题:
EXEC tSQLt.NewTestClass @ClassName = N'errtest';
GO
CREATE OR ALTER PROCEDURE errtest.test_simple
AS
BEGIN
PRINT('Executing errtest.test_simple');
CREATE TABLE Actual (
A INT,
B NVARCHAR(10));
CREATE TABLE Expected (
A INT,
B NVARCHAR(10));
BEGIN TRY
DECLARE @IntegerVariable AS INT;
SET @IntegerVariable = 'a string';
PRINT('There were no errors.');
END TRY
BEGIN CATCH
PRINT('An error happened.');
END CATCH
DECLARE @AssertType NVARCHAR(100);
SET @AssertType = 'AssertAssertEqualsTableSchema';
--SET @AssertType = 'AssertEquals';
IF @AssertType = 'AssertEquals' BEGIN
PRINT('ASSERT: Equals for 2 INTs');
EXEC tSQLt.AssertEquals @Expected = 1
,@Actual = 1
,@Message = N'no'
END
ELSE BEGIN
PRINT('ASSERT: EqualsTableSchema');
EXEC tSQLt.AssertEqualsTableSchema @Expected = N'Expected'
,@Actual = N'Actual'
,@Message = N'Hallo'
END
END
GO
EXEC tSQLt.Run 'errtest.test_simple';
如果这是安装了 tSQLt 的 运行,我会得到以下结果:
Executing errtest.test_simple
An error happened.
ASSERT: EqualsTableSchema
[errtest].[test_simple] failed: (Error) The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.[16,1]{tSQLt.AssertEqualsTableSchema,7} (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,187})
+----------------------+
|Test Execution Summary|
+----------------------+
|No|Test Case Name |Dur(ms)|Result|
+--+-----------------------+-------+------+
|1 |[errtest].[test_simple]| 3|Error |
----------------------------------------------------------------------------------------
Msg 50000, Level 16, State 10, Line 47
Test Case Summary: 1 test case(s) executed, 0 succeeded, 0 skipped, 0 failed, 1 errored.
----------------------------------------------------------------------------------------
但是,如果我取消注释行 --SET @AssertType = 'AssertEquals';
,更简单的断言 tSQLt.AssertEquals 运行s 没有错误并通过了测试:
Executing errtest.test_simple
An error happened.
ASSERT: Equals for 2 INTs
+----------------------+
|Test Execution Summary|
+----------------------+
|No|Test Case Name |Dur(ms)|Result |
+--+-----------------------+-------+-------+
|1 |[errtest].[test_simple]| 7|Success|
----------------------------------------------------------------------------------------
Test Case Summary: 1 test case(s) executed, 1 succeeded, 0 skipped, 0 failed, 0 errored.
----------------------------------------------------------------------------------------
这里列出了在上面的示例中哪些断言有效,哪些无效。
工作:AssertEquals、AssertEqualsString、AssertNotEquals、AssertObjectDoesNotExist、AssertObjectExists、失败(未使用断言)→ 测试通过
不工作:
AssertEqualsTableSchema、AssertEmptyTable、AssertEqualsTable、AssertLike、AssertResultSetsHaveSameMetaData
问题是 tSQLt 启动了一个事务——这是必需的,因此可以回滚伪造的对象并删除它创建的任何辅助对象。但是 try catch 中的错误可能会导致交易失败。 tSQLt.AssertEqualsTableSchema
尝试插入表 tSQLt.Private_AssertEqualsTableSchema_Expected
和 tSQLt.Private_AssertEqualsTableSchema_Actual
,这将写入日志文件,因此出现错误。
作为解决方法,您可以在不触及事务日志的情况下自行检查。下面的示例(基于 tSQLt 所做的 SELECT
)
IF EXISTS (SELECT *
FROM (
SELECT
C.object_id,
RANK()OVER(PARTITION BY C.object_id ORDER BY C.column_id) AS col_ordinal,
C.name,
CAST(C.system_type_id AS NVARCHAR(MAX))+QUOTENAME(TS.name) system_type_id,
CAST(C.user_type_id AS NVARCHAR(MAX))+CASE WHEN TU.system_type_id<> TU.user_type_id THEN QUOTENAME(SCHEMA_NAME(TU.schema_id))+'.' ELSE '' END + QUOTENAME(TU.name) user_type_id,
C.max_length,
C.precision,
C.scale,
C.collation_name,
C.is_nullable
FROM sys.columns AS C
JOIN sys.types AS TS
ON C.system_type_id = TS.user_type_id
JOIN sys.types AS TU
ON C.user_type_id = TU.user_type_id
WHERE C.object_id IN ( OBJECT_ID('dbo.Expected'), OBJECT_ID('dbo.Actual'))
) T
GROUP BY col_ordinal, name, system_type_id, user_type_id, max_length, precision, scale, collation_name, is_nullable
HAVING COUNT(*) = 1
)
EXEC [tSQLt].Fail 'Unexpected/missing column(s)'
显然,上面的内容可以更详细地return具体差异的更多细节,并将其本身移动到存储过程中以方便重复使用。
似乎 SQL 测试框架 tSQLt 不允许在生成错误的 TRY/CATCH 块之后使用诸如 tSQLt.AssertEqualsTableSchema 的断言。如果我尝试这样做,测试会生成错误而不是 pass/fail 结果。另一方面,更简单的断言如 tSQLt.AssertEquals 在这种情况下有效,通过了测试。
我想知道在这种情况下是否有办法使用这样的断言语句,或者它是否是 tSQLt 的基本限制并且它不起作用。
此代码重现了问题:
EXEC tSQLt.NewTestClass @ClassName = N'errtest';
GO
CREATE OR ALTER PROCEDURE errtest.test_simple
AS
BEGIN
PRINT('Executing errtest.test_simple');
CREATE TABLE Actual (
A INT,
B NVARCHAR(10));
CREATE TABLE Expected (
A INT,
B NVARCHAR(10));
BEGIN TRY
DECLARE @IntegerVariable AS INT;
SET @IntegerVariable = 'a string';
PRINT('There were no errors.');
END TRY
BEGIN CATCH
PRINT('An error happened.');
END CATCH
DECLARE @AssertType NVARCHAR(100);
SET @AssertType = 'AssertAssertEqualsTableSchema';
--SET @AssertType = 'AssertEquals';
IF @AssertType = 'AssertEquals' BEGIN
PRINT('ASSERT: Equals for 2 INTs');
EXEC tSQLt.AssertEquals @Expected = 1
,@Actual = 1
,@Message = N'no'
END
ELSE BEGIN
PRINT('ASSERT: EqualsTableSchema');
EXEC tSQLt.AssertEqualsTableSchema @Expected = N'Expected'
,@Actual = N'Actual'
,@Message = N'Hallo'
END
END
GO
EXEC tSQLt.Run 'errtest.test_simple';
如果这是安装了 tSQLt 的 运行,我会得到以下结果:
Executing errtest.test_simple
An error happened.
ASSERT: EqualsTableSchema
[errtest].[test_simple] failed: (Error) The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.[16,1]{tSQLt.AssertEqualsTableSchema,7} (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,187})
+----------------------+
|Test Execution Summary|
+----------------------+
|No|Test Case Name |Dur(ms)|Result|
+--+-----------------------+-------+------+
|1 |[errtest].[test_simple]| 3|Error |
----------------------------------------------------------------------------------------
Msg 50000, Level 16, State 10, Line 47
Test Case Summary: 1 test case(s) executed, 0 succeeded, 0 skipped, 0 failed, 1 errored.
----------------------------------------------------------------------------------------
但是,如果我取消注释行 --SET @AssertType = 'AssertEquals';
,更简单的断言 tSQLt.AssertEquals 运行s 没有错误并通过了测试:
Executing errtest.test_simple
An error happened.
ASSERT: Equals for 2 INTs
+----------------------+
|Test Execution Summary|
+----------------------+
|No|Test Case Name |Dur(ms)|Result |
+--+-----------------------+-------+-------+
|1 |[errtest].[test_simple]| 7|Success|
----------------------------------------------------------------------------------------
Test Case Summary: 1 test case(s) executed, 1 succeeded, 0 skipped, 0 failed, 0 errored.
----------------------------------------------------------------------------------------
这里列出了在上面的示例中哪些断言有效,哪些无效。
工作:AssertEquals、AssertEqualsString、AssertNotEquals、AssertObjectDoesNotExist、AssertObjectExists、失败(未使用断言)→ 测试通过
不工作: AssertEqualsTableSchema、AssertEmptyTable、AssertEqualsTable、AssertLike、AssertResultSetsHaveSameMetaData
问题是 tSQLt 启动了一个事务——这是必需的,因此可以回滚伪造的对象并删除它创建的任何辅助对象。但是 try catch 中的错误可能会导致交易失败。 tSQLt.AssertEqualsTableSchema
尝试插入表 tSQLt.Private_AssertEqualsTableSchema_Expected
和 tSQLt.Private_AssertEqualsTableSchema_Actual
,这将写入日志文件,因此出现错误。
作为解决方法,您可以在不触及事务日志的情况下自行检查。下面的示例(基于 tSQLt 所做的 SELECT
)
IF EXISTS (SELECT *
FROM (
SELECT
C.object_id,
RANK()OVER(PARTITION BY C.object_id ORDER BY C.column_id) AS col_ordinal,
C.name,
CAST(C.system_type_id AS NVARCHAR(MAX))+QUOTENAME(TS.name) system_type_id,
CAST(C.user_type_id AS NVARCHAR(MAX))+CASE WHEN TU.system_type_id<> TU.user_type_id THEN QUOTENAME(SCHEMA_NAME(TU.schema_id))+'.' ELSE '' END + QUOTENAME(TU.name) user_type_id,
C.max_length,
C.precision,
C.scale,
C.collation_name,
C.is_nullable
FROM sys.columns AS C
JOIN sys.types AS TS
ON C.system_type_id = TS.user_type_id
JOIN sys.types AS TU
ON C.user_type_id = TU.user_type_id
WHERE C.object_id IN ( OBJECT_ID('dbo.Expected'), OBJECT_ID('dbo.Actual'))
) T
GROUP BY col_ordinal, name, system_type_id, user_type_id, max_length, precision, scale, collation_name, is_nullable
HAVING COUNT(*) = 1
)
EXEC [tSQLt].Fail 'Unexpected/missing column(s)'
显然,上面的内容可以更详细地return具体差异的更多细节,并将其本身移动到存储过程中以方便重复使用。