用Sqlite的内存数据库对nhibernate进行单元测试

针对数据访问代码的单元测试处在一个尴尬的位置上,如果操作不是针对真实的数据库执行的,就无法捕获数据库特定的错误,比如 sql 语句语法是否正确,操作是否违反了数据库约束,事务是否正确提交。并且,测试之间应该是隔离的,一个测试不能影响另一个测试的数据,就是说,每个测试运行之前都要重建表结构,重新安装测试数据。在一个真实的数据库上执行这些操作会让测试成为老牛破车。

所幸的是Sqlite提供了内存数据库,避免磁盘IO可以带来性能提升。内存数据库有一个非常重要的特点:即数据库仅在连接打开的时候存在,一旦连接关闭,数据库随即消失。这正是我们想要的,运行测试的步骤如下:

1,在 [TestInitialize] 方法中打开 Session,创建表结构,安装测试数据。默认情况下,Sqlite的Unicode字符串比较是区分大小写的,所以,创建表结构的时候要为 TEXT 列指定 COLLATE NOCASE。

2,运行测试

3,在 [TestCleanup] 方法中关闭 Session,这将导致底层的连接关闭,内存数据库消失。

代码如下:

    [TestClass]
    public class MyTest
    {
        [AssemblyInitialize]
        public static void InitAssembly(TestContext testContext)
        {
            NHibernateHelper.Init();
        }

        [AssemblyCleanup]
        public static void CleanupAssembly()
        {
            NHibernateHelper.CloseSessionFactory();
        }


        protected ISession Session { get; private set; }

        [TestInitialize()]
        public void MyTestInitialize()
        {
            
            try
            {
                // 1 打开 Session
                Session = NHibernateHelper.OpenSession();

                // 2 创建表
                NHibernate.Tool.hbm2ddl.SchemaExport export = new NHibernate.Tool.hbm2ddl.SchemaExport(NHibernateHelper.Configuration);
                export.SetDelimiter(";");

                StringWriter sw = new StringWriter();
                export.Execute(false, false, false, Session.Connection, sw);

                using (IDbCommand cmd = Session.Connection.CreateCommand())
                {
                    // 替换字段定义语句
                    cmd.CommandText = Regex.Replace(sw.ToString(), @"\s+TEXT\s+", " TEXT COLLATE NOCASE ", RegexOptions.IgnoreCase | RegexOptions.Compiled);
                    cmd.ExecuteNonQuery();
                }

                // 3 创建测试数据
                using (ITransaction tx = Session.BeginTransaction())
                {
                    Role role = new Role();
                    role.Name = "admins";
                    Session.Save(role);

                    tx.Commit();
                }



                // 4 清除 Session 缓存
                Session.Clear();
            }
            catch (Exception ex)
            {
                // 如果发生异常,则 TestCleanup 不会执行,因此在这里回收资源

                if (Session != null)
                {
                    Session.Close();
                }
                throw;
            }
        }

        [TestCleanup()]
        public void MyTestCleanup()
        {
            Session.Close();
            Session = null;
        }


        [TestMethod]
        public void MyTestMethod()
        {
            using (ITransaction tx = Session.BeginTransaction())
            {
                Role role = Session.Query<Role>().FirstOrDefault(x => x.Name == "admins");
                Assert.IsNotNull(role);

                tx.Commit();
            }


        }
    }

NHibernate 配置,注意 connection.release_mode 属性一定要设为 on_close

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <bytecode-provider type="null"/>
  <reflection-optimizer use="false"/>
  <session-factory>
    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="connection.driver_class">NHibernate.Driver.SQLite20Driver</property>
    <property name="connection.connection_string">
      data source=:memory:
    </property>
    <property name="dialect">NHibernate.Dialect.SQLiteDialect</property>
    <property name="connection.release_mode">on_close</property>
    <property name="hbm2ddl.keywords">none</property>
    <property name="current_session_context_class">managed_web</property>
    <property name="show_sql">false</property>
    <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
    <property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
    <mapping assembly="WuTong"/>
  </session-factory>
</hibernate-configuration>

参考链接:

http://ayende.com/blog/3983/nhibernate-unit-testing

http://www.sqlite.org/faq.html#q18

posted @ 2011-07-29 12:33  梦幻泡影  阅读(758)  评论(0编辑  收藏  举报