我如何单元测试持久性?

作为实践测试驱动开发的新手,我经常会在如何单元测试持久性到数据库时遇到困难。

我知道在技术上这将是一个集成测试(不是单元测试),但我想找出以下最佳策略:

  1. 测试查询。
  2. 测试插入。如何知道如果插入失败会出错?我可以通过插入然后查询来测试它,但我怎么知道查询没有错?
  3. 测试更新和删除 - 与测试插入
  4. 相同

做这些的最佳做法是什么?


关于测试SQL:我知道这可以完成,但是如果我使用像NHibernate这样的O / R映射器,它会在用于输出查询的别名中附加一些命名瑕疵,因为这有点不可预知,我不确定我可以测试一下。

我应该放弃一切,只要相信NHibernate?我不确定这是否审慎。

0
额外 编辑
意见: 3

10 答案

看看DB Unit。它是一个Java库,但必须有一个C#等价物。它允许您使用一组数据来准备数据库,以便您知道数据库中的内容,然后可以与DB单元进行交互以查看数据库中的内容。它可以针对许多数据库系统运行,因此您可以使用实际的数据库设置,或使用其他内容,例如Java中的HSQL(具有内存选项的Java数据库实现)。

如果你想测试你的代码是否正确地使用了数据库(你很可能应该这样做),那么这是隔离每个测试并确保数据库预期数据准备好的方法。

0
额外

技术上持久性单元测试不是单元测试,而是集成测试。

在使用mbUnit的C#中,只需使用SqlRestoreInfo和RollBack属性即可

    [TestFixture]
    [SqlRestoreInfo(, ,]
    public class Tests
    {

        [SetUp]
        public void Setup()
        {

        }

        [Test]
        [RollBack]
        public void TEST()
        {
           //test insert. 
        }
    }

在NUnit中也可以做到这一点,excpet的属性名称略有不同。

至于检查您的查询是否成功,您通常需要按照第二个查询来查看数据库是否已按预期更改。

0
额外

您可以通过嘲笑数据库连接来进行单元测试。这样,您就可以构建方法调用流程中的特定查询成功或失败的场景。我通常建立我的模拟期望值,以便忽略实际的查询文本,因为我真的想测试方法的容错性以及它如何处理自身 - SQL的具体细节与此无关。

很明显,这意味着你的测试不会真正验证方法的效果,因为SQL可能是错误的。这就是集成测试的起点。为此,我希望别人能有一个更彻底的答案,因为我刚开始接触到这些人。

0
额外

对于 NHibernate ,我肯定会主张嘲笑单元测试的 NHibernate API - 相信库做正确的事情。如果你想确保数据真正进入数据库,请执行集成测试。

0
额外

我也会模拟数据库,并检查查询是否您所期望的。测试检查错误的sql有风险,但是这可以在集成测试中检测到

0
额外

我在这里写了一篇关于单元测试的文章数据层涵盖了这个确切的问题。 (可耻的)插头道歉,但文章太长,无法在此发布。

我希望这能帮到你 - 在过去的6个月里,我在3个活跃的项目中工作得很好。

问候,

Rob G

0
额外

我单元测试持久性时遇到的问题,特别是没有ORM并因此模拟数据库(连接)时,您不知道您的查询是否成功。这可能是因为您的查询是专门为特定数据库版本设计的,只能使用该版本。如果你嘲笑你的数据库,你永远不会发现。所以在我看来,单元测试的持久性只有有限的用处。您应该始终添加针对目标数据库运行的测试。

0
额外
我同意,虽然我从来没有成为TDD纯粹主义者,但我肯定看到了TDD的许多好处,但忽略了现实,并没有真正测试你的数据进出数据库,你不知道你的应用程序真的要做什么在野外。在我得到一个分配给我的“bug”之前的很多次,我的代码不工作,我会运行我的单元测试,发现另一个开发人员踩到我的sproc(恶魔sprocs)并从未关心运行我的单位测试看到他们破坏了整个系统。
额外 作者 Chris Marisic,

对于基于JDBC的项目,可以使用Acolyte框架: http://acolyte.eu.org 。它允许模拟想要测试的数据访问,从JDBC抽象中受益,而无需管理特定的测试数据库。

0
额外

我通常创建一个存储库并使用它来保存我的实体,然后检索一个新的实体。然后我断言检索到的就等于保存的。

0
额外

正如 Mike Stone所说,DbUnit非常适合将数据库变为在运行测试之前已知状态。测试完成后,DbUnit可以将数据库恢复到运行测试前的状态。

DbUnit(Java)

DbUnit.NET

0
额外