数据库交互代码

时间:2010-07-27 21:23:39

标签: database unit-testing oop

我正在编写一个适用于数据库的小应用程序,但我无法确定如何测试此交互。 我的应用程序依赖于5个存储过程,我决定将它们封装在一个类中。 该类提供了5个执行过程的公共方法,并在必要时将结果转换为对象集合。

我真的无法弄清楚如何以简单的方式测试我的代码,我想我可能犯了一些错误。

您如何看待我的设计?有没有更好的方法来处理这些案件?

非常感谢您的帮助

编辑: 在我的存储过程中,只有“插入”和“选择”查询。

4 个答案:

答案 0 :(得分:2)

一般情况下,我建议不要针对实时数据库进行测试,原因如下:

  1. 执行SQL可以使您的测试花费很长时间
  2. 数据可能会在您的鼻子下发生变化,即使没有明显的代码更改也会导致测试失败。您希望测试具有隔离性和确定性,因此只有在代码更改时才会通过或失败。
  3. 如果您有更新数据库的代码,则需要回滚更改,否则下一次测试运行可能会导致误报或误报。
  4. 因此,对于测试,您希望伪造数据库。从这样的事情开始:

    public interface IDataRepository {
        Customer GetCustomerByName(string name);
        void SaveCustomer(Customer c);
        SecurityToken Login(string username, string password);
    }
    
    class DatabaseRepository : IDataRepository { ... } // invokes your stored procedures
    

    如果您的类需要数据库中的某些内容,请将IDataRepository传递给对象的构造函数。

    关于此设置的好处是如何创建实现相同接口的FakeDataRepository - 它不会调用任何内容,只返回硬编码数据。您可以为快乐案例,异常案例和其他需求返回数据。

    换句话说,您根本不测试类和数据库之间的交互 ​​- 单元测试的目的是测试单个功能而不关心应用程序中的其他移动部件。


    现在,如果您需要来测试存储过程,您应该直接为DatabaseRepository类编写测试。

    您需要在每次测试后将数据库重新设置为其原始状态 - 因此您要么在事务中运行并回滚所有内容,要么在每次测试运行时创建一个包含临时数据的新数据库。我更喜欢后一种方法 - 它太容易让事务处于打开状态或忘记将其回滚,因此会破坏所有测试数据。

    这样的数据库测试可能需要花费任意长的时间来执行,因此您最好创建一个严格用于测试数据库的单独项目(特别是如果您有几百个存储过程)。

    我认为这更像是系统或集成测试,而不是单元测试。

答案 1 :(得分:0)

在处理数据库和逻辑时,我经常使用自动集成测试。一般的想法是使用应用程序的模式设置测试数据库。在测试脚本中,您可以填充测试数据库。设置好所有内容后,将您的类与测试数据库一起使用,以测试一切正常。更改数据并再次测试。

在每次测试运行期间,您需要注意创建和销毁测试数据库。您不需要先前测试的数据,否则您无法精确测试存储过程。

由于集成测试中的参与者多于单元测试,因此您需要进行更多的设置和清理工作。

您可以使用单元测试来测试您的类,模拟数据库连接,但这不会验证存储过程是否正常工作。不是为存储过程编写单元测试,而是进行集成测试通常更容易。

答案 2 :(得分:0)

首先,你应该让自己成为developer database。您可以使用内存数据库,但我发现让真实的数据库实例生活在开发环境中的某个地方会更好。 要明确这一点 - 您的开发人员数据库而不是共享实例。

接下来,您需要确保此类可以注入其设置。至少这意味着一个额外的构造函数,它接受一个连接字符串,所以在测试期间你可以将它指向你的开发人员数据库。

您的代码有三个需要测试的项目。首先是物体编组;第二个是打到数据库,最后你有异常处理。可能值得自己测试每个项目。如果是这样,将编组拆分为他们自己的方法,采用DataRow或ResultSet并将其公开。

测试数据库的第二个项目(一个集成测试,但是有用的一个 - 并且dev数据库越接近生活越好。如果你在实时使用Oracle,请使用Oracle作为开发人员数据库) 。这意味着您需要设置数据库。我目前手动使架构保持最新,并使用dbUnit等工具自动设置数据。这可以清除数据,使用XML填充表并根据XML文件验证表。

最后你有异常处理,要做到这一点,你需要注入除连接设置以外的东西,而是注入IDbConnection或Connection,这样你就可以在你需要的时候让连接抛出异常(假设你这样做)对于异常有特殊之处,如果你只是记录它们并让它们冒泡它可能不值得测试。

答案 3 :(得分:-1)

为什么不调用每个方法,而这些方法又调用存储过程并通过迭代集合来检查结果?如果结果很多,请限制为测试目的而返回的数字。

现在,如果您正在尝试验证数据的质量,我认为这不是正确的方法。