2012-06-27 42 views
6

有没有办法为SSMS中的SQL查询创建简单的单元测试?我对T-SQL & SSMS相当陌生,但如果可能的话,我想尝试将一些旧的TDD习惯带入这个舞台。所以,例如,当我编写DDL来创建复杂的函数和什么不是,我想有一些方法来包含一个单元测试(在失败时)实际上会导致输出面板显示一个执行时出错消息。 (这将是analagous在正常编程环境“破坏构建”)SQL Server Management Studio中的单元测试

目前,当我写一个函数,语法正确,然后按F5来执行它,输出信息是:

Command(s) completed successfully. 

我在寻找的是一些简单的SQL技巧来模拟基本的红光/绿光测试案例。所以我会编写一系列测试语句,只有当我的用户定义的函数按预期运行时才会通过测试语句。否则,将显示一条错误消息,如:

Msg 207, Level 16, State 1, Line 2 
Invalid statement. 

这将让我立即跳转到失败的测试,看看我做错了什么。

我不希望这里有任何“内置”的东西,但有什么办法可以“伪造”吗?

更新:我刚刚得知你可以在throw exceptions SS2012,我敢肯定,我可以用眼前这个目的,但不幸的是我坚持用SS2008现在。在SS2008中有什么可比的?

+0

更新:我刚刚遇到了这个有用的文章:[“SQL Server中的测试驱动设计入门”](http://www.sqlmag.com/print/sql-server/test-driven-design-sql -server-142881) – kmote

回答

6

这些是2个框架我可以建议更换

T.S.T.

http://tst.codeplex.com/

测试SQL Server代码与TST

http://www.infoq.com/articles/tst-sql-server

tSQLt

http://tsqlt.org/

SQL测试(转轮tSQLt)

http://www.red-gate.com/products/sql-development/sql-test/

更新1

阅读你的答案也许您会发现以下转储有用。

TRY CATCH是在SQL Server 2005中引入的(因此,我们不应该在2005年以前看过)。您可以使用存储过程中提到的存储过程实际(重新)抛出异常,包括行号。在SQL Server 2012中,他们(finaly!)引入了抛出,正如你提到在14年后使Tsql成为一种强大的语言。

所以这里是我的转储,我需要清理它的一天所以它更复制粘贴友好。

SET XACT_ABORT ON 
SET CONCAT_NULL_YIELDS_NULL OFF 

DECLARE @message varchar (max) 
DECLARE @who varchar (255) 
set @who = OBJECT_NAME(@@PROCID) -- name of the currently executing sproc 

BEGIN TRY 

-- ====================================================================================== 
SET @message = 'HELLO' 
EXEC Log @who, @message 

     .... 

-- ====================================================================================== 
SET @message = 'GOODBYE' 
EXEC Log @who, @message 

END TRY 

BEGIN CATCH 


     -- ====================================================================================== 
--If an error generated in a TRY block causes the state of the current transaction to be invalidated, the transaction is classified as an uncommittable transaction. 
--An error that ordinarily ends a transaction outside a TRY block causes a transaction to enter an uncommittable state when the error occurs inside a TRY block. 
-- http://msdn.microsoft.com/en-us/library/ms175976.aspx 
     if XACT_STATE() = -1 rollback; 

    -- ====================================================================================== 
SET @message = 'Rolling Back transaction if present' 
EXEC Log @who, @message 

    -- Its important to rollback the transaction at the very start of the catch. 
-- Otherwise the records that are written to the log will also be roll backed. 

IF @@TRANCOUNT > 0 
BEGIN 
ROLLBACK TRAN 
END 

-- ====================================================================================== 
SET @message = 'Error Occured ' 
set @message = @message + ' ERROR_NUMBER() : ' + cast(ERROR_NUMBER() as varchar(max)) 
set @message = @message + ' ERROR_SEVERITY() : ' + cast(ERROR_SEVERITY() as varchar(max)) 
set @message = @message + ' ERROR_STATE() : ' + cast(ERROR_STATE() as varchar(max)) 
set @message = @message + ' ERROR_PROCEDURE() : ' +cast(ERROR_PROCEDURE() as varchar(max)) 
set @message = @message + ' ERROR_LINE() : ' + cast(ERROR_LINE() as varchar(max)) 
set @message = @message + ' ERROR_MESSAGE() : ' + cast(ERROR_MESSAGE() as varchar(max)) 

EXEC Log @who, @message 

    exec usp_RethrowError 


END CATCH 


Error logging sproc and table 

CREATE PROCEDURE [dbo].[Log] 
(
@who varchar(255), 
@message varchar(max) 
) 
AS 

SET XACT_ABORT ON 
SET CONCAT_NULL_YIELDS_NULL OFF 

INSERT INTO [ApplicationLog] 
(
[Date], 
[Level], 
[Logger], 
[Host], 
[Message] 
) 
VALUES 
(
getDate(), 
'INFO', 
@who, 
'dummy', 
@message 
) 

CREATE TABLE [dbo].[ApplicationLog] (
[Id]   [int] IDENTITY(1, 1) NOT NULL, 
[Date]   [datetime] NOT NULL, 
[Thread]  [varchar](255) NULL, 
[Level]   [varchar](50) NOT NULL, 
[Logger]  [varchar](255) NOT NULL, 
[Host]   [varchar](50) NOT NULL, 
[Message]  [varchar](max) NOT NULL, 
[Exception]  [varchar](max) NULL 
) 


Rethrow an exception 

ALTER PROCEDURE [dbo].[usp_RethrowError] 
-- BOL contains a good example of that, there is a stored procedure called usp_RethrowError 

AS -- Return if there is no error information to retrieve. 

SET XACT_ABORT ON 
SET CONCAT_NULL_YIELDS_NULL OFF 

IF ERROR_NUMBER() IS NULL 
    RETURN ; 

DECLARE @ErrorMessage NVARCHAR(4000), 
    @ErrorNumber INT, 
    @ErrorSeverity INT, 
    @ErrorState INT, 
    @ErrorLine INT, 
    @ErrorProcedure NVARCHAR(200) ; 

    -- Assign variables to error-handling functions that 
    -- capture information for RAISERROR. 
SELECT @ErrorNumber = ERROR_NUMBER(), @ErrorSeverity = ERROR_SEVERITY(), 
     @ErrorState = ERROR_STATE(), @ErrorLine = ERROR_LINE(), 
     @ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-') ; 

    -- Building the message string that will contain original 
    -- error information. 
SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 
     'Message: ' + ERROR_MESSAGE() ; 

    -- Raise an error: msg_str parameter of RAISERROR will contain 
    -- the original error information. 
RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, -- parameter: original error number. 
    @ErrorSeverity, -- parameter: original error severity. 
    @ErrorState, -- parameter: original error state. 
    @ErrorProcedure, -- parameter: original error procedure name. 
    @ErrorLine-- parameter: original error line number. 
     ) ; 
+0

当我第一次问这个问题时,我只是在寻找一些可能完成我所陈述的任务而不是完整的框架的“一行”。但是这些建议很棒 - 我必须去探索它们。谢谢! – kmote

+0

我是C#开发人员,我几乎总是用那种语言来做我的逻辑,所以我可以进行单元测试。但是,当处理1亿行数据时,transact sql可以使得处理小时数或12小时之间有所不同。尽管我必须依赖自己的迷你框架,但至今仍然存在这些框架。我虽然玩了上述2,但他们完成了这项工作。 – buckley

+0

感谢您的更新,这导致我在[BOL](http://msdn.microsoft.com/en-us/library/ms179296(v = sql.105).aspx)中对“usp_RethrowError”的原始描述。非常有趣的东西!我不确定我目前的情况如何使用它,但我可以看到它可能在未来非常有用。 – kmote

0

嗯,我已经找到了一个可能的解决方案,我自己的问题:RAISERROR。该“工程”在一定程度上(至少在我invisioning的方式),让我建立基本的测试,如:

IF dbo.myTestedFunction(@parm) != @myExpectedResult 
    RAISERROR('>> Unit Test FAILED! -- %d, 11, 0, @parm) 

这是离奇,但它确实显示,我可以点击一个错误信息跳到违规的代码行(在我的情况下,这是失败的单元测试) - 虽然在第一行有一些虚假信息。

+0

我更新了我的答案,如果你需要(重新)抛出sql> 2005并且想要访问最初导致异常的行号(这里是C#行话) – buckley

相关问题