tSQLt是SQL Server存储过程自动化单元测试的必需框架,因其纯数据库内运行、支持FakeTable/ExpectException/事务隔离,能精准覆盖临时表、OUTPUT参数、错误抛出及权限验证等手写脚本无法可靠处理的场景。

SQL Server 存储过程的自动化单元测试,必须用 tSQLt;其他方式(比如手写事务脚本、外部 Python 调用)要么漏断言、要么难隔离、要么无法验证错误抛出和临时表行为。
为什么不能只用 EXEC + 临时表手动比对
很多人尝试用 DECLARE @rc INT; EXEC @rc = dbo.usp_GetUserById @id = 123; 捕获返回值,再把结果插入 #actual 表和 #expected 对比。这看似可行,但实际踩坑密集:
- 没处理
OUTPUT参数——必须显式声明变量并加OUTPUT关键字,漏写就捕获不到 - 结果集排序不一致导致比对失败——
tSQLt.AssertEqualsTable自动忽略顺序,手写EXCEPT会因行序不同误报 - NULL 值语义错乱——手写
IS NULL判断容易漏掉三值逻辑,tSQLt内部用INTERSECT和NOT EXISTS精确处理 - 测试后数据残留——没
ROLLBACK或没在事务里执行,下个测试读到脏数据
tSQLt 安装失败的三个硬性前提
tSQLt.Install() 报错,90% 是卡在这三步没做全:
- 数据库兼容级别必须 ≥ 100(即 SQL Server 2008 及以上),查
SELECT compatibility_level FROM sys.databases WHERE name = DB_NAME(); -
sp_configure 'clr enabled', 1; RECONFIGURE;必须执行,且需sysadmin权限 - 开发/测试库要
ALTER DATABASE [YourDB] SET TRUSTWORTHY ON;;生产环境禁用此设置,得改用证书签名方式加载程序集
如果遇到 “Could not load file or assembly”,检查下载的 tSQLt 版本是否匹配 SQL Server 实际版本——例如 SQL Server 2019 CU20 应用 tSQLt v1.0.8+,对应 .NET Framework 4.6.1。
测试含 OUTPUT 参数或临时表的过程时的关键陷阱
存储过程里用了 CREATE TABLE #temp 或 @out_param VARCHAR(50) OUTPUT,直接测会失败:
-
tSQLt.FakeTable 'dbo.Orders'只伪造永久表,对#temp无效——得把临时表逻辑拆进独立过程,或改用表变量@table_var(tSQLt可正常处理) -
OUTPUT参数必须在EXEC时显式传入变量,不能省略OUTPUT关键字,否则参数值不会回写 - 若过程内部有
INSERT ... EXEC调用另一个过程,tSQLt默认禁止嵌套EXEC,需提前用tSQLt.ApplyConstraint解除限制
示例:测 usp_GetOrderSummary @order_id = 100, @total = @total OUT,必须写成:
DECLARE @total DECIMAL(10,2); EXEC dbo.usp_GetOrderSummary @order_id = 100, @total = @total OUTPUT; -- 后续用 tSQLt.AssertEquals @Expected = 299.99, @Actual = @total;
别在测试里调用真实表或依赖全局状态
哪怕只是 SELECT TOP 1 * FROM dbo.Users,也会让测试不可重复——今天跑过,明天因数据变更就失败。正确做法是:
- 所有依赖表必须先
tSQLt.FakeTable 'dbo.Users',再INSERT测试数据 - 避免用
GETDATE()或NEWID()——改用tSQLt.SpyProcedure拦截系统函数,或传入固定时间参数 - 权限相关逻辑(如
IF IS_ROLEMEMBER('db_datareader') = 0 RAISERROR)必须用tSQLt.SetFakeLogin模拟不同登录上下文
最易被忽略的是:测试类 schema 名必须以 test_ 开头,且测试存储过程名也必须以 test_ 开头,否则 tSQLt.Run 找不到用例。

















