单元测试和存储过程

时间:2009-07-14 16:41:02

标签: unit-testing stored-procedures data-access-layer

如何对使用存储过程调用的代码进行单元测试?

在我的应用程序中,我使用了大量的单元测试(NUnit)。对于我的DAL,我使用DevExpress XPO ORM。 XPO的一个好处是它允许您使用内存中的数据存储。这允许我在测试装置中设置测试数据,而不需要对数据库具有外部依赖性。

然后,来了优化!对于我们应用程序的某些部分,我们不得不求助于通过ORM替换操作数据的代码来调用T-SQL存储过程。那当然通过添加一个新的外部依赖来打破我们可测试的代码。我们不能只是“模拟”存储过程调用,因为我们正在测试数据操作的副作用。

我已经计划最终用LINQ to SQL替换我对XPO的使用; LINQ to SQL似乎允许我比XPO更好的查询功能,无需一些存储过程。我希望如果我转换到LINQ to SQL,我将能够让我的单元测试使用LINQ to Objects来避免数据库依赖。但是,我怀疑所有spoc都可以被LINQ to SQL替换。

我应该:

  • 咬住子弹并更改我的一些测试装置,以便他们创建SQL Server数据库,
  • 创建数据库单元测试,而不是测试代码,
  • 或跳过测试这些孤立的事件,因为它们不值得吗?

我也很想知道您的备用设置,其中存储过程与您的可测试代码和平共存。

1 个答案:

答案 0 :(得分:2)

我使用的方法是在调用另一个方法或类后面的存储过程时封装逻辑层。然后,您可以测试数据库层逻辑,与测试应用程序逻辑分开。这样,您可以为服务器端(数据库)应用程序逻辑的客户端应用程序逻辑和集成测试创建单独的单元测试。给出一段利用存储过程调用的代码,如下所示:

class foo:

    prop1 = 5

    def method1(listOfData):
        for item in listOfData:
            dbobj.callprocedure('someprocedure',item+prop1)

可以重构将对远程系统的调用封装到它自己的方法中:

class foo:
    prop1 = 5
    def method1(listOfData):
        for item in listOfData:
            someprocedure(item+prop1)

    def someprocedure(value):
        dbobj.callprocedure('someprocedure',value)

现在,当您编写单元测试时,请模拟someprocedure()类方法,以便它实际上不会进行数据库调用。然后创建一组单独的集成测试,这些测试需要一个已配置的数据库,该数据库调用someprocedure()的实际版本,然后验证数据库是否处于正确的状态。