65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 SqlCE 和 NHibernate 进行 TDD

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.42/5 (7投票s)

2007 年 4 月 10 日

CPOL

4分钟阅读

viewsIcon

56849

downloadIcon

422

本文介绍了在使用 TDD 时设置 SqlCE 测试平台的流程。

引言

本文演示了如何使用 SQL Compact Edition 对存储库/DAO 类进行数据库单元测试。 如今,我一想到要对开发数据库进行数据库测试就感到不寒而栗。 以易于理解和逻辑的方式,在可丢弃的数据源上执行数据库测试会更好。 这就是内存数据库和嵌入式数据库发挥作用的地方。

背景

当我刚开始寻找内存/嵌入式数据库的选项时,我偶然发现了 Ayende Rahien 的 博客文章,内容是关于内存数据库与嵌入式数据库的。 我将让您阅读该文章以获取更多信息,而不是在此讨论
此处存在差异。 关键在于,有许多选项,并且由于 NHibernate,任何一个都可以集成到此解决方案中。 同样,如果您不熟悉 NHibernate,可以访问 Hibernate 网站了解更多信息。

我之所以选择 SqlCe,是因为它设置起来最简单,对各种数据类型有最好的支持,并且它是嵌入式的。 因此,您可以在运行测试开始时在 TestFixtureSetUp 中创建数据库,插入记录并运行断言,然后处理数据库文件。 我本想使用内存数据库,但我查看的唯一一个 Sqlite 文档很少,而且存在一些其他缺点。 此时,我做了一些关于 SqlCe 的研究,并看到了它的设置和运行有多么容易。

Using the Code

代码非常基础。 我将简要介绍一下。 假设您对 NHibernate、NUnit 和 TDD 有一定的了解。

代码的核心部分来自 Ayende 的 Rhino.Commons 库。 我删除了相关部分,因为他还提供了一些用于测试期间数据库清理/持久化的附加功能,这些功能与基本概念无关。 我建议您查看他的类,因为它们非常完善且易于理解。 您可以在 此处找到 Ayende 的 Rhino.Commons。 嵌入式 TestFixture 位于 ForTesting 目录下的 此处SqlCeDBHelper 位于 Helpers 目录下的 此处

在附带的代码中,我已将 EmbeddedTestBase 设置为数据单元测试的基类。 在此类中,您可以指定数据库文件名

public static string DatabaseFilename = "TempDB.sdf";

SDF 数据库文件将放在测试程序集的 bin 目录中。 文件位置无关紧要,因为它在每次通过 SqlCEDbHelper 启动测试时都会被删除。

这里的关键是 FixtureInitalize(params Assembly[] assemblies),您可以在此处看到它

/// <summary> 
/// Initialize NHibernate and builds a session factory 
/// Note, this is a costly call so it will be executed only one. 
/// </summary> 
protected void FixtureInitalize(params Assembly[] assemblies) {
    if (sessionFactory != null)
        return;

        Hashtable properties = new Hashtable();
        properties
        .Add("hibernate.connection.driver_class",
            "NHibernate.Driver.SqlServerCeDriver");
        properties
            .Add("hibernate.dialect",
            "NHibernate.Dialect.MsSqlCeDialect");
        properties
        .Add("hibernate.connection.provider",
                "NHibernate.Connection.DriverConnectionProvider");
        string connectionString =
        string.Format("Data Source={0};", DatabaseFilename);
        properties
        .Add("hibernate.connection.connection_string",
        connectionString);
        properties
        .Add("hibernate.show_sql", "true");
        properties
        .Add("hibernate.connection.release_mode",
        "on_close");

        configuration = new Configuration();
        configuration.Properties = properties;
        foreach (Assembly assembly in assemblies) {
            Console.WriteLine("Adding Assembly:" + assembly);
            configuration = configuration.AddAssembly(assembly);
        }
        sessionFactory = configuration.BuildSessionFactory();
}

以及 CreateSession();,显示在此处

public ISession CreateSession() {
    SetupDb();
    return sessionFactory.OpenSession();
}

当您调用 CreateSession 时,它首先调用 Ayende 的 SqlCEDbHelper.SetupDb(),该方法将通过反射创建将使用的数据库文件。 接下来,它使用 NHibernate 的 SchemaExport 创建架构。

public void SetupDb() {
    SqlCEDbHelper.CreateDatabaseFile(DatabaseFilename);
    try {
        new SchemaExport(configuration)
        .Execute(false, true, false, true);
    }
    catch (Exception e) {
        Console.WriteLine("Error Message:" + e);
    }
}

在您的测试类中,您可以像这样调用 FixtureInitializeCreateSession

[TestFixtureSetUp]
public void TestFixtureSetUp() {
    FixtureInitalize(typeof(User).Assembly);

    session = CreateSession();
    userRepository = new UserRepository();
    userRepository.session = session;
}

当您调用 FixtureInitialize 时,您可以将映射文件所在程序集的引用传递给它,该程序集将用于创建架构。 在示例代码中,它与当前程序集相同,但在任何实际情况下,它都将位于单独的程序集中。 此方法还将构建 NHibernate SessionFactory

最后,调用 sessionFactory.OpenSession(),它将返回要使用的 NHibernate 会话。

在我的测试的 SetUp 方法中,我首先将要测试的记录插入数据库。 我认为这可以以更好的方式完成,因为需要运行一个方法来确保数据库在每次测试运行开始时都处于一致状态。 在将来的版本中,我可能会在基类中引入另一个方法来在每次测试后“重置”数据库。

关注点

实际上,UserRepository 以及您可能拥有的任何其他 Repository/Dao 类都将继承自一个通用的基类,该基类将公开 GetByIdGetAll 等,而不是将 session 对象用于所有 NHibernate 访问。 为简单起见,我已省略了这些详细信息。 有关如何实现 GenericDao 的更多信息,请参阅 Bill McCafferty 的最新 NHibernate Best Practices 文章

我在他的文章中使用了许多 Bill 阐述的技术,这些技术对于轻松测试您的 Dao 非常有用,例如分离接口、使用 Castle Windsor 进行 IoC 以及 NHibernateSessionManager。 利用所有这些工具将使测试您的 Repositories/Dao 更加容易。

如果您使用的是 SQL 关键字,请务必添加反引号 "`"。 我在第一次尝试此操作时遇到了一个问题,并盯着它看了很长时间,以至于我都没注意到。 不幸的是,SqlCe 在此错误方面并不太有信息量。 我只得到一个“token error”。 感谢 Ayende 在我抓耳挠腮几个小时后帮我解决这个问题。

下次我希望写一篇关于如何使用 NUnit 有效测试 Castle MonoRail Controller 的文章! 敬请期待!

历史

  • 2007 年 4 月 10 日 - 文章首次发布
© . All rights reserved.