tsqlt 是 sql server 存储过程单元测试的合理选择,因其纯数据库内运行、原生支持临时表/faketable/expectexception/事务隔离,精准覆盖权限、触发器、错误抛出等场景。

为什么 tSQLt 是 SQL Server 存储过程单元测试的合理选择
tSQLt 是专为 SQL Server 设计的开源单元测试框架,它不依赖外部应用层(如 C# 或 Python),所有测试都在数据库内运行,能直接验证 INSERT、UPDATE、SELECT 逻辑、事务行为、错误抛出等真实数据库操作。如果你的存储过程涉及临时表、表变量、权限检查或触发器联动,用外部工具 mock 很难覆盖,而 tSQLt 的 tSQLt.FakeTable、tSQLt.ExpectException 和事务隔离机制天然适配这些场景。
安装 tSQLt 并启用 CLR 权限的实操要点
tSQLt 本质是一组 T-SQL 对象(函数、存储过程、架构),但部分功能(如捕获结果集比对)依赖 CLR 程序集。安装失败通常卡在这三步:
- 确保数据库处于
TRUSTWORTHY ON状态(仅开发/测试环境允许;生产应改用证书签名方式):ALTER DATABASE [YourDB] SET TRUSTWORTHY ON;
- 执行
tSQLt.Install()前,必须先启用clr enabled配置:sp_configure 'show advanced options', 1; RECONFIGURE; sp_configure 'clr enabled', 1; RECONFIGURE;
- 若遇到“无法加载程序集”错误,检查 SQL Server 版本与下载的 tSQLt .NET Framework 版本是否匹配(例如 SQL Server 2019 推荐用 tSQLt v1.0.8+,对应 .NET Framework 4.6.1)
编写一个验证错误抛出的存储过程测试用例
假设你有一个存储过程 usp_TransferFunds,要求当余额不足时抛出消息为 'Insufficient balance' 的错误。不能只查返回值,必须验证 RAISERROR 是否被触发且内容精确匹配:
EXEC tSQLt.NewTestClass 'test_usp_TransferFunds';<br><br>CREATE PROCEDURE test_usp_TransferFunds.[test throws error when balance too low]<br>AS<br>BEGIN<br> -- Arrange<br> EXEC tSQLt.FakeTable @TableName = 'Accounts';<br> INSERT INTO Accounts (AccountId, Balance) VALUES (1, 50.0);<br><br> -- Act & Assert<br> EXEC tSQLt.ExpectException @ExpectedMessage = 'Insufficient balance';<br> EXEC usp_TransferFunds @FromId = 1, @ToId = 2, @Amount = 100.0;<br>END;
注意:tSQLt.ExpectException 默认只匹配错误消息子串,若需全等匹配,加参数 @ExpectedMessagePattern = 0;若要校验错误号,用 @ExpectedErrorNumber。
测试含临时表或输出参数的存储过程时的典型陷阱
临时表(#temp)在 tSQLt 测试中默认不可见,因为每个测试运行在独立事务中,而临时表作用域受限于会话——但 tSQLt 会切换上下文,导致 #temp 在 EXEC 内创建后,在后续语句中丢失。解决方法只有两个:
- 改用表变量(
@tempTable),它支持跨批作用域,且 tSQLt 兼容性好 - 如果必须用临时表,把整个逻辑封装进另一个存储过程,再用
tSQLt.SpyProcedure拦截调用并验证输入参数
对于输出参数,别用 SELECT 返回值去断言,而是显式声明变量接收:
DECLARE @Result INT;<br>EXEC usp_CalculateTax @OrderTotal = 1000.0, @Tax OUT;<br>EXEC tSQLt.AssertEquals 80.0, @Tax;
测试里所有对象(表、视图、过程)都自动挂到 tSQLt_test_* 架构下,不会污染生产对象,但这也意味着你不能在测试里直接引用未 fake 的同名生产表——漏掉 tSQLt.FakeTable 是最常被忽略的初始化步骤。










