接受在我最喜欢的C ++上使用单元测试的便利之后,我试图将自己的经验转移到TSQL,尤其是因为新雇主热衷于实地的一项有用计划并为此分发面包。
我浏览了几个
著名的框架,得出的结论是,它们通常是笨重的,并带来了需要进一步研究的其他语法。
向他们展示了一些框架,它们工作得很漂亮,并且吸引了经理的注意,但是有一些我不喜欢的限制。
我想在纯洁清真-东正教TSQL上实现所有功能。
我不时地因磨练脚本的结构而分散了数年的主要开发工作,因此我决定与您共享该脚本(但仍然设法产生了3.5 Mb的脚本)。
我的基本要求很简单-我必须在文件中执行任何单元测试,而无需任何手势和特殊的软件工具-仅限于核心:sqlcmd或MSSMS。
不会对执行测试的数据库进行任何更改-所有内容都会回滚到脚本的开头。
只有一个限制:测试应该在空数据库中工作(可能是初始数据),否则您会厌倦拆卸所有选项。
主要任务是测试逻辑并维护逻辑的完整性。
为此,我将以下标题放在测试的开头:
SET QUOTED_IDENTIFIER ON GO PRINT '-------------------------------- CLR Unit tests for Habr Logic ---------------------------------' IF 0 < ( SELECT count(*) FROM device) begin RAISERROR ('FAILED: database must be empty for this unit test', 16, -1 ) end GO
我尝试创建单元测试的时间不要超过几个屏幕,尽管在复杂逻辑的情况下这并不容易。
一个典型的单元测试如下所示,它包含三个关键部分:
BEGIN TRAN TestClr2 declare @test_name sysname = (select TOP 1 name from sys.dm_tran_active_transactions WHERE transaction_type = 1 ORDER BY transaction_begin_time DESC) + ' [fn_calculate_dev_status] record for device has wrong range' BEGIN TRY SET NOCOUNT ON;
-1.准备用于单元测试的数据在这里,我们可以用数据填充必要的表,并准备一些临时变量或表,以免使测试部分中的代码混乱。
-2.执行单元测试如果我们测试触发逻辑的话,通常是函数调用,过程或表更改。
-3.结果验证在测试的这一部分中,我们检查数据库对象的状态如何改变,或者测试功能过程的结果。
如果过程函数返回一条记录,则我们将其插入临时表并已对其进行分析。
将汇总和准备的结果与标准进行比较,如果其他所有方法均失败,则抛出异常。
使用Oracle,一切都变得有些复杂-我无法以那种形式和相同的意识形态来编写和运行测试,而只是出于一点经验-我们不再为产品支持Oracle。
每个单元测试均按以下程序发布:
CREATE OR REPLACE PROCEDURE UnitTest9_TRG_JOBLOGDETAIL AS v_message VARCHAR2(255) := 'UnitTest9_TRG_JOBLOGDETAIL: INSERT joblogdetail]- joblogdetail_result not Failed and joblogdetail_endtime is null '; v_maxdate date := '2014/01/01'; v_cnt NUMBER := 0; BEGIN savepoint my_savepoint; <b>
最后,在同一测试文件中,您将必须从创建和执行的测试中进行数据库清除。
commit; / set serveroutput on; SET FEEDBACK OFF; spool C:\dist\test.spl; exec UnitTest_empty_database; exec UnitTest3297_TRGBFR_UDEVICE(1); exec UnitTest5_TRG_BF_UDEVICE; exec UnitTest_3062a; ... spool off; / DROP PROCEDURE UnitTest_3062; DROP PROCEDURE UnitTest_BIRDIESEC_3344; DROP PROCEDURE UnitTest_empty_database; ... SET FEEDBACK ON; commit;
仅此而已。
然后,您只需生成文件,将其分为以下类型的类别:触发器,函数,过程,报告,业务逻辑的大型和特殊对象,当然还有每个数据库对象。
几乎所有的数据库开发人员都皱着眉头说-为什么我应该让测试人员这样做呢? 如果数据库根本没有单词的逻辑,那么我同意它们,但是如果数据库中有很多逻辑,那么它们自然就可以省去神经,声誉和金钱。
一个例子。
在Web界面中,我们在树对象(例如,美国->加拿大->安大略->亚洲滑铁卢->日本->东京-> Ebina)之间建立了逻辑连接树,即整个地理办公室。
每个这样的节点都有非常复杂的规则,用户或规则或生成器会分配设备。
结果,即使在步骤中详细描述的指令也会破坏每个人,甚至是那些参与讨论和开发此逻辑的人。
带有不同数据集的指令的五十多个步骤-详细记录了所有内容。
逻辑上的任何更改或补充都是手动验证的时钟,没有任何故障。
死亡重构类似。
在用单元测试介绍了逻辑之后,一切都由Silk进行了检查,并且我确定一切都可以正常工作。
任何运行Java的Java开发人员都可以通过运行适当的测试来轻松地摆弄雷电(思考自己弯曲的手)。
几分钟,每个人都很满意。 在我不在的情况下,任何致命的代码更改都会通过邮件快速向我报告。
自然,作为一个懒惰的人,我决定自动化Continuous Automation的所有内容,并用批处理和python编写粥。
我要求您稍微执行一下,在每天要发展的十几种语言和环境中,您必须抽空来舔所有的东西并将它们放在专业的外观中,这是灾难性的。
我不想在Windows Powershell上做任何事情-我们的跳过程序仍然在嵌入式Windows95上到处运行。
我想用Python进行所有调用,但事实证明,不仅在python库中,而且在.NET中均不支持某些sql(在cte中进行XML解析)构造,因此我通过sqlcmd进行了脚本编写。
代码在
这里发布。
要运行一个有效的示例,只需编辑2个文件:smtppart.py和config.ini-SMTP服务器名称,端口和电子邮件,将在其中放置错误消息。
脚本首先尝试从svn获取最新更新(替换为您自己的-git,perforce等)。
然后从具有随机名称的脚本创建一个干净的基础,在其中启动单元测试,然后删除该基础。
创建一个包含80 Mb脚本和3.5 Mb测试的数据库(该方案的主要部分已经在我加入公司之前完成,因此我仅测试了自己的一部分)在大约15分钟的时间内在我的计算机上完成。 在最后提交之前,我只是有时间喝一杯咖啡。
如果有错误,则错误结果将发送到电子邮件。
依赖项安装在文件readme.txt中进行了描述
每次更改代码后,您都必须在config.ini文件中手动设置代码哈希(将在命令行中看到)-即使代码已更改且没有任何损坏,消息仍会出现-因此我可以控制代码中的更改,以便可以检查更改而无需我以前的参与。

可以将autorun.bat文件中所有单元测试的启动放置在
Windows Task Scheduler中,以在公司组建之前一天或在离开家后一天运行1-2次-如果晚上出现故障-您可以查看电视前发生的情况并迅速进行修复。
我知道在单元测试中,最困难的是设置所有内容,然后编写测试很容易,虽然这可能很困难,但很必要。 祝您测试顺利,希望我的建议对您有所帮助。
如果某些地方可以改进并梳理代码,我会很乐意提意见,请不要严格判断。