【问题标题】:Integration testing in .net with nhibernate使用 nhibernate 在 .net 中进行集成测试
【发布时间】:2010-11-09 03:40:59
【问题描述】:

我一直在为我的最新项目做一些诚实的 TDD,我很喜欢它,以前做过单元测试但不是认真的 TDD,我发现它很有帮助。

我的项目的一些背景:

  • ASP.Net 前端-
  • NHibernate 用于与 SQL Server 2008 express 进行数据库交互-
  • 用于在 NUnit 中完成并通过 resharper 运行的域逻辑和单元测试的 C# 4.0 DLL。
  • 运行 NAnt 构建脚本的 Teamcity CI 服务器。

我现在处于某种“alpha”版本,我发现所有错误都是集成错误,主要是因为我的集成测试是手动使用网站,以及一些小的自动化测试(我已经停止跑步)。考虑到我对测试套件的严格程度以及我想要纠正它,这非常糟糕。

我的问题是,进行集成测试的最佳方法是什么,或者我可以阅读任何文章。我知道在 ASP.NET Webforms 中测试 UI 将是一件痛苦的事情(将来会转移到一个更可测试的框架,但一次一步)。但我想确保我与 hibernate 的交互得到了正确的测试。

所以我需要一些关于集成测试的技巧

  • 休眠(缓存、会话等)-
  • 测试数据,我发现 'NDBUnit' 是我应该考虑使用什么来使我的数据处于良好状态?这与 NHibernate 兼容吗?
  • 我应该将数据库换成 SQLite 还是什么?或者只是设置另一个仅保存测试数据的 SQL 服务器数据库?
  • 如何使这些测试可维护?我进行了一些集成测试,但它们给我带来了麻烦,我发现自己避开了它们。我认为这主要是由于我没有每次都设置一致的状态。

只是一些一般性的建议也很好,我已经阅读了 Kent Beck 的 TDD 示例和 Roy Osherove 的单元测试艺术,它们非常适合单元测试/tdd,但我很想阅读更多关于集成测试和编写它们的策略(你应该测试什么等)---

【问题讨论】:

    标签: c# .net testing integration-testing


    【解决方案1】:

    关于数据库部分:
    - 您可以直接按照本文所述使用它:Unit testing with built-in NHibernate support.
    - 使用 SQLite 加速测试也非常有用。只有在这种情况下,您应该意识到您不再真正针对实际生产配置。
    - SQLite 不支持 SQL Server 支持的所有功能。 This article 显示了切换到 SQLite 所需的测试设置的代码示例 - 它非常简单直接。
    - NDbUnit 作为一种准备测试数据的机制也是一个不错的选择 - 只要您不希望在您的 Db 上频繁更改架构(在这种情况下,维护所有相关的 xml 会变得相当多的工作文件...)。
    关于 ASP.NET 部分:
    - 您可能会发现像 Selenium 这样的工具对 UI 驱动的测试很有帮助。

    HTH!
    托马斯

    【讨论】:

    • 如果您使用 VS2010(ultimate/premium) - 您也可以使用 Coded UI 进行 UI 测试。
    • @Ahmad。这不是仅适用于 TFS 吗?因此,您需要为此准备好整个 TFS 基础架构吗?
    • 不——我们上周五进行了演示。演示者使用他的笔记本电脑并给出了一个从头到尾的演示,所以我对此非常确定。另一方面是编码的 ui 测试可以使用 nant、msbuild 等自动化,类似于您的正常单元测试。归根结底,它只是测试代码......
    • @Ahmad。感谢您提供信息-对此不确定。关于自动化方面:Selenium 是一个框架,您只需从常规测试方法中调用它 - 所以这里也没有自动化问题......
    • 谢谢 Thomas,我之前在 JSP 项目中使用过 Selenium,维护起来有点麻烦,但我想维护成本会节省我每次手动测试 UI 的时间,所以我可能会看看它。感谢有关 NDBUnit 的 hte 建议,也许我可以在 SQL Server 中创建一个测试数据库而不是 sqlite 来开始 - 将使过渡更顺畅,然后如果测试运行太慢,我可以考虑更改。
    【解决方案2】:

    聚会有点晚了,但这是我一段时间以来一直在做的事情。

    我正在编写 REST API,供我们的移动应用使用。移动应用程序也是用 C# 编写的,因此编写 API 包装器 (SDK) 对我来说很有意义。

    在集成测试时,我设置了测试用例来测试 API 的所有端点,使用 SDK。运行测试时,API 在我的本地 IIS 上以开发模式运行。每次启动服务器时,我的开发数据库都会被擦除、重新创建并为所有表添加数据,这给了我一个有点现实的场景。我也不必担心测试更新/删除,因为只需要重建服务器项目,NHibernate 将删除、创建和播种我的数据库。如果需要,这可以更改为每个请求。

    在测试我的存储库时,了解我的查询是否可以被 NHibernate 翻译对我来说很重要,因此我所有的存储库测试都使用 LocalDB,每个测试用例都会重新创建它。这意味着每个测试用例都可以设置查询测试成功所需的种子数据。

    另一件事,当您使用真实数据为您的数据库播种时,您还可以免费测试您的外键设置。此外,播种器正在使用您的域类,所以看起来也不错!

    播种机示例:

    public void Seed(ISession s) 
    {
      using(var tx = s.BeginTransaction() 
      {
        var account1 = new Account { FirstName = "Bob", LastName = "Smith" };
        var account2 = new Account { FirstName = "John", LastName = "Doe" };
        account1.AddFriend(account2); // manipulates a friends collection
        s.Save(account1);
      }
    }
    

    您应该在创建会话工厂时调用播种器。

    重要提示:设置是通过 IoC 容器完成的。

    【讨论】:

      【解决方案3】:

      简短的回答是:不要进行集成测试。

      我们有以下设置:

      • 我们的单元测试尽可能少地测试。我们只测试业务代码的一个功能(不是直接的方法,而是更多的逻辑功能);

      • 为业务代码的每个功能编写单元测试;

      • 为业务代码的不同功能之间的交互编写单元测试;

      • 确保这些测试涵盖所有内容。

      这将为您提供一组涵盖所有内容的单元测试。

      我们确实有集成测试,但这些测试是写在 Word 文档中的,而且通常只是原始规范。 QA 人员会在代码交付时运行这些程序,并且大多数情况下它只是正常工作,因为我们已经测试了每一个小部分。

      在 InfoQ 上,有一个很棒的演示文稿很好地解释了这种工作方式:Integration Tests Are a Scam

      关于测试 NHibernate 的一件事。我们已经申请了repository pattern。这样做是我们的 NHibernate 查询变得非常非常简单,例如:

      public class NhRepository<T> : IRepository<T>
      {
          public T Get(int id)
          {
              return GetSession().Get<T>(id);
          }
      }
      
      public interface IUserRepository : IRepository<User>
      {
          IEnumerable<User> GetActiveUsers();
      }
      
      public class UserRepository : NhRepository<User>, IUserRepository
      {
          public IEnumerable<User> GetActiveUsers()
          {
              return
                  from user in GetSession().Users
                  where user.IsActive
                  return user;
          }
      }
      

      这与Windsor IoC 容器相结合提供了我们的数据访问。这个设置的问题是:

      1. 查询非常简单(无论如何,其中有 98%),我们没有彻底测试它们。这听起来可能很奇怪,但我们更倾向于使用同行评审来测试这些,而不是任何其他机制;

      2. 这些存储库很容易被模拟。这意味着对于上面的存储库,我们有一个类似这样的模拟:

        var repositoryMock = mocks.StrictMock<IUserRepository>();
        
        var activeUsers = new List<User>();
        
        for (int i = 0; i < 10; i++)
        {
            var user = UserMocks.CreateUser();
            user.IsActive = true;
            activeUsers.Add(user);
        }
        
        Expect.Call(repositoryMock.GetActiveUsers()).Return(activeUsers);
        

        实际的代码要简洁得多,但你明白了。

      【讨论】:

      • 你是说 InfoQ 演示文稿?
      • 感谢 Pieter,该设置几乎正是我正在使用的,Windsor、Rhino Mocks、NHibernate 与 Repository 模式,仅对域的广泛覆盖,数据库的模拟。我是这个项目的单人团队,所以我没有任何 QA 部门来进行手动测试,所以我现在几乎是手动测试。您如何调试集成问题?例如,nhibernate 使用空白构造函数 + 属性,并以这种方式创建对象,或者您是否对这些对象进行单元测试并尝试准确复制 nhibernate 在您的单元测试代码中所做的事情?
      • 我伪造了 NHibernate 所做的事情。我创建了一组实体模拟工厂,它们为我构建了假模拟。我创建了两种类型的模拟:一种非常简单,对我的域约束无效,另一种是有效的。我用来构建有效实体的无效实体,因为我需要设置所有属性。这样,当我需要单个实体时,我确保不会在内存中构建整个数据库。当我需要实体属性中的集合时,我会即时构建它们。这样我就可以像 NHibernate 那样加载实体了。
      • 认真的吗?不写集成测试?我希望看到一个项目,仅使用单元测试进行正确测试。问题就变成了,你对你的模拟有多少信任?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-14
      • 2019-12-17
      • 2020-05-12
      • 1970-01-01
      • 2013-04-07
      • 2019-12-17
      • 2015-12-28
      相关资源
      最近更新 更多