测试存储过程的最佳方法是什么?

时间:2008-09-29 02:59:33

标签: sql-server

像许多需要通过存储过程进行所有访问的公司一样,我们似乎已经将大量业务逻辑锁定在sprocs中。这些东西很难测试,其中一些变得很傻。有没有人有一套最佳实践可以让你更容易自信地测试这些东西?

目前我们维护了30个左右的“问题”数据库。这并不总是特别好记录,并且确实不会自动化。

8 个答案:

答案 0 :(得分:10)

一位同事在TSQLUnit testing framework发誓。可能值得一看你的需求。

答案 1 :(得分:4)

我们有一个非常薄的数据访问层,它基本上使存储过程看起来像C#方法。然后我们的NUnit测试套件使用SetUp / TearDown来创建/回滚调用DAL的事务和测试方法。没什么好看的,并且证明比TSQLUnit测试套件更容易维护。

答案 2 :(得分:2)

不确定这是否是您正在寻找的,但是因为您正在使用SQL Server:我发现LINQ是一个很棒的工具测试存储过程。您只需将存储过程拖到DBML图上,然后在datacontext上将它们作为方法调用即可。节拍为测试工具设置ADO连接等。例如,如果在Visual Studio中设置测试项目,则可以像在另一个对象上的方法一样测试您的过程。如果您的存储过程返回结果集,我认为LINQ会将其转换为您应该能够通过IEnumerable或IQueryable访问的匿名变量(有人请验证这一点)。但如果你只返回返回代码,这应该是一种快速而简单的方法。

答案 3 :(得分:2)

我注意到你的帖子被标记为SqlServer。如果是这种情况,那么您应该查看属于Visual Studio的Database Professional for Database Professionals。这是一些文章:

最后一个实际上是跨数据库平台,而DBPro现在只是SQL Server。

答案 4 :(得分:2)

我使用的一种方法是编写一个“临时”单元测试来重构特定的存储过程。您可以从数据库中的一组查询中保存数据,并将它们存储在单元测试可以获取的位置。

然后,重构您的proc库存。返回的数据应该相同,并且可以自动或手动直接与保存的数据进行比较。

另一种方法是并行运行两个存储过程,并比较结果集。

这对于仅限选择的存储过程尤其有效,但更新,插入和更新删除更复杂。

我已经使用这种方法将代码置于一个更容易进行单元测试或更简单,或两者兼而有之的状态。

答案 5 :(得分:2)

尝试TST。您可以从以下网址下载并安装:http://tst.codeplex.com/

答案 6 :(得分:1)

这似乎是一个糟糕的政策。也许您可以编写一个执行SQL的存储过程,并开始转换代码以在那里运行。

无论如何,我会测试通过传统的自动化框架调用存储过程。作为应用程序和数据之间的网关,这些应该作为集成测试来处理,而不是纯单元测试。但是,您可以使用基于xUnit的单元测试框架来驱动它们。只要您的测试有权对数据库运行SQL,可能通过我之前提到的方法,您应该能够断言正确的更改。

一个挑战是你表明他们变得越来越长。我建议将它们分解为子程序并使它们尽可能小。它使测试更容易,也更容易维护。

答案 7 :(得分:1)

这是我的低技术,快速方法,只是保持示例输入方便地位于DDL


USE [SpacelySprockets]

GO
/****** Object: StoredProcedure [dbo].[uspBrownNoseMrSpacely] Script Date: 02/03/3000 00:24:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
--================================
--Stored Procedure DDL:
--================================ --Example Inputs
/*
DECLARE @SuckupPloyId int
DECLARE @SuckupIdentityRecordId int
SET @SuckupPloyId = 3
*/ -- =============================================
-- Author: 6eorge Jetson
-- Create date: 01/02/3000
-- Description: Sucks up to the boss
-- =============================================
CREATE PROCEDURE [dbo].[uspBrownNoseMrSpacely]
@SuckupPloyId int
,@SuckupIdentityRecordId int OUTPUT
AS
BEGIN DECLARE @EmployeeId int DECLARE @SuckupPoints int DECLARE @DateTimeStamp datetime SET @EmployeeId = dbo.svfGetEmployeeId('6eorge Jetson') SET @SuckupPoints = dbo.svfGetSuckupPoints(@SuckupPloyId) SET @DateTimeStamp = getdate() --Data state-changing statement in sproc INSERT INTO [dbo].[tblSuckupPointsEarned]([EmployeeId], [SuckupPoints], [DateTimeStamp] ) VALUES (@EmployeeId, @SuckupPoints, @DateTimeStamp) SET @SuckupIdentityRecordId = @@Identity END
--Unit Test Evidence Display /* SELECT @EmployeeId as EmployeeId ,@SuckupPoints as SuckupPoints ,@DateTimeStamp as DateTimeStamp */ --========================================================================== --After editing for low-tech, non-state changing "unit-like" test invocation --========================================================================== --Example Inputs DECLARE @SuckupPloyId int DECLARE @SuckupIdentityRecordId int SET @SuckupPloyId = 3 /* -- ============================================= -- Author: 6eorge Jetson -- Create date: 01/02/3000 -- Description: Sucks up to the boss -- ============================================= CREATE PROCEDURE [dbo].[uspBrownNoseMrSpacely] @SuckupPloyId int ,@SuckupIdentityRecordId int OUTPUT AS BEGIN */ DECLARE @EmployeeId int DECLARE @SuckupPoints int DECLARE @DateTimeStamp datetime SET @EmployeeId = dbo.svfGetEmployeeId('6eorge Jetson') SET @SuckupPoints = dbo.svfGetSuckupPoints(@SuckupPloyId) SET @DateTimeStamp = getdate() --Data state-changing statement now commented out to prevent data state change -- INSERT INTO [dbo].[tblSuckupPointsEarned]([EmployeeId], [SuckupPoints], [DateTimeStamp] ) -- VALUES (@EmployeeId, @SuckupPoints, @DateTimeStamp) SET @SuckupIdentityRecordId = @@Identity --END --Need to comment out the sproc "END" also --Unit Test Evidence Display SELECT @EmployeeId as EmployeeId ,@SuckupPoints as SuckupPoints ,@DateTimeStamp as DateTimeStamp

对于udfs来说效果更好,因为不需要担心状态的变化。 显然,我不建议这样做代替测试框架, 但如果我坚持这个简单的秒成本纪律

断言我的可管理大小的sproc至少通过了一个简单的“单元测试”

在执行CREATE PROCEDURE之前,我发现我犯了更少的错误(可能是因为纪律比测试本身更多)。