【问题标题】:How to effectively Unit Test a DAL that uses ADO.NET and SQL Server with NUnit?如何有效地对使用 ADO.NET 和 SQL Server 和 NUnit 的 DAL 进行单元测试?
【发布时间】:2012-07-29 19:24:17
【问题描述】:

因此,您在 C# 中有一个使用存储库模式的 DAL,并且每个存储库都有一个接口。它由 ADO.NET、MS SQL Server 和存储过程调用提供支持。

这非常适合在进行单元测试时对正在使用它的存储库进行存根/模拟,我喜欢它!

但是,我希望为 DAL 本身添加一些单元测试。最好使用带有 NUnit 的 Rhino Mocks。但是,如果可以证明它可以做 Rhino 在这个问题上做不到的事情,我愿意切换到 MoQ。

我宁愿在单元测试期间不让它与任何数据库对话,以保持它们更“纯”,同时仍然有效地测试 DAL 本身。但是,如果您不能真正有效地对 DAL 本身进行单元测试而不与 DB 对话,那么在内存替换或基于可移植文件的替换中,与 SQL Server 和相同的 SqlConnection 和 SqlCommand 调用兼容的替代方案是什么。

如果需要,可以对 DAL 进行重构,以使其更易于注入,只要它不会同时使设计过于复杂。已经在使用 Microsoft Unity,用于具有存储库模式的 DI。

【问题讨论】:

    标签: unit-testing c#-4.0 mocking nunit data-access-layer


    【解决方案1】:

    那些单元测试究竟会测试什么?考虑到典型的 DAL 代码,除了将实际工作委派给第 3 方数据访问代码(ADO.NET、EntityFramework、NHibernate)之外,其他事情很少。

    我没有太多使用 ADO.NET,但我想这个 NHibernate 示例已经足够了:

    public User GetUser(int id)
    {
        using (var session = sessionFactory.OpenSession())
        {
            return session.Get<User>(id);
        }
    }
    

    当然,假设代码编写正确,所有依赖项(即sessionFactory)都将通过接口传递,因此易于存根,因此编写单元测试是可能的(您将只需要模拟很多东西来实现它)。

    纯粹的方法是编写这样的单元测试,因为它是另一个数据点,证明您的代码确实符合您的假设(调用Get)。但是,请注意,这样的测试相当昂贵,因为您基本上必须对您的提供者进行的整个数据库访问进行存根(模拟 sessionFactory 以返回模拟会话,然后检查是否进行了调用)。

    这是一个艰难的决定(在这种情况下是否遵循纯粹的方法),因为无论如何您都必须使用真实数据库编写integration tests。这些测试将涵盖与您编写的单元测试完全相同的领域,但在真实环境中工作(而不是存根环境)。

    根据我的经验,单元测试 DAL 通常不值得它提供的好处,特别是与它相当高的成本(为单元测试编写代码以存根数据库环境所花费的时间)和存在适当的集成测试套件相比时。

    最后,我建议不要在任何类型的测试中使用内存数据库。原因如下:

    • 很慢
    • 它有几个可能难以控制的故障点(ORM 配置、内存数据库设置、可能无效的测试数据)
    • 让您误以为进行集成测试(而您没有这样做;内存数据库的行为可能与您的真实生产数据库完全不同)

    除非您可以将完全相同的数据库加载到内存中,否则请坚持使用适当的集成测试(这将是 DAL 测试优先级)和独立的单元测试备份(前提是您有能力编写它们)。

    【讨论】:

    • 对不起,如果我不清楚,它只是 ADO.NET、SQL Server 和存储过程,根本没有 ORM。单元测试将测试您的 SQL 是否有效,并且您正在将结果从 SQL 转换为存储库接口返回的 POCO。您要确保 DAL 具有有效的 SQL 语句并正确传递参数,并且数据类型的转换按预期工作。
    • @RodneyFoley:是的,编写这样的测试的成本仍然很高(存根任何种 ORM 或 ADO 代码都很难)。你基本上完成了集成测试要做的事情。请注意,这些测试将非常脆弱,因为 SQL 的最轻微变化(例如格式),即使应用程序工作不会产生任何变化,也会破坏单元测试。我不是说“不要那样做”;我警告说这些测试会很昂贵,并且集成测试中已经有便宜的替代品(无论如何你都应该拥有)。
    • 我同意您在回答中的陈述。我想我要做的是针对它们正确转换的类型转换编写单元测试,然后将其余部分推送到我们的集成测试并完成。更糟糕的是,对于快速的开发人员完整性检查,我可能会编写一些单元测试,它们实际上是一个带有忽略标志的集成测试,因此我们可以在签入前对 SQL 语句进行更改时根据需要运行。感谢 Jimmy!
    猜你喜欢
    • 2011-02-20
    • 2010-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多