50

作为一名实践测试驱动开发的新手,我经常陷入困境,即如何对数据库的持久性进行单元测试。

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

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

做这些的最佳实践是什么?


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

我应该放弃一切并简单地信任NHibernate吗?我不确定这是否谨慎。

4

10 回答 10

18

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

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

于 2008-08-11T09:40:44.607 回答
16

As Mike Stone said, DbUnit is great for getting the database into a known state before running your tests. When your tests are finished, DbUnit can put the database back into the state it was in before you ran the tests.

DbUnit (Java)

DbUnit.NET

于 2008-08-25T13:22:46.733 回答
4

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

显然这意味着您的测试实际上不会验证该方法是否有效,因为 SQL 可能是错误的。这就是集成测试开始的地方。为此,我希望其他人会有更彻底的答案,因为我自己才刚刚开始掌握这些。

于 2008-08-05T09:47:41.013 回答
3

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

I hope that helps you - it has worked very well for me over the last 6 months on 3 active projects.

Regards,

Rob G

于 2008-08-12T23:23:30.933 回答
2

我在对持久性进行单元测试时遇到的问题,尤其是在没有 ORM 并因此模拟您的数据库(连接)的情况下,您并不真正知道您的查询是否成功。可能是您的查询是专门为特定数据库版本设计的,并且仅在该版本上成功。如果你模拟你的数据库,你永远不会发现这一点。因此,在我看来,单元测试持久性的用途有限。您应该始终添加针对目标数据库运行的测试。

于 2008-08-05T10:29:42.880 回答
2

对于NHibernate,我肯定会提倡只是嘲笑NHibernate APIfor 单元测试——相信库会做正确的事情。如果要确保数据实际进入数据库,请进行集成测试。

于 2008-08-05T11:20:38.330 回答
2

For JDBC based projects, my Acolyte framework can be used: http://acolyte.eu.org . It allows to mockup data access you want to tests, benefiting from JDBC abstraction, without having to manage a specific test DB.

于 2014-07-09T09:20:23.467 回答
1

我还会模拟数据库,并检查查询是否符合您的预期。存在测试检查错误 sql 的风险,但这会在集成测试中检测到

于 2008-08-05T10:19:08.563 回答
1

从技术上讲,持久性的单元测试不是单元测试。它们是集成测试。

在 C# 中使用 mbUnit,您只需使用SqlRestoreInfoandRollBack属性:

    [TestFixture]
    [SqlRestoreInfo(<connectionsting>, <name>,<backupLocation>]
    public class Tests
    {
      
        [SetUp]
        public void Setup()
        {
        
        }

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

在 NUnit 中也可以这样做,只是属性名称略有不同。

至于检查,如果您的查询成功,您通常需要在其后进行第二次查询,以查看数据库是否已按预期更改。

于 2008-08-05T11:27:08.550 回答
1

I usually create a repository, use that to save my entity and retrieve a fresh one. Then I assert that the retrieved is equal to the saved.

于 2008-08-27T21:17:21.787 回答