使用 Fluent nHibernate 进行单元测试 - 删除每个测试可能性的数据

本文关键字:测试 可能性 数据 删除 nHibernate Fluent 单元测试 使用 | 更新日期: 2023-09-27 17:59:42

我已经为我的Fluent NHibernate数据库设置了一些内存SQLite单元测试,看起来像这样。它工作正常。(使用NUnit (

namespace Testing.Database {
    /// <summary>
    /// Represents a memory only database that does not persist beyond the immediate
    /// testing usage, using <see cref="System.Data.SQLite"/>.
    /// </summary>
    public abstract class InMemoryDatabase : IDisposable {
        /// <summary>
        /// The configuration of the memorized database.
        /// </summary>
        private static Configuration Configuration { get; set; }
        /// <summary>
        /// The singleton session factory.
        /// </summary>
        protected static ISessionFactory SessionFactory { get; set; }
        /// <summary>
        /// The current session being used.
        /// </summary>
        protected ISession Session { get; set; }
        protected InMemoryDatabase() {
            SessionFactory = CreateSessionFactory();
            Session = SessionFactory.OpenSession();
            BuildSchema(Session);
        }
        /// <summary>
        /// Construct a memory based session factory.
        /// </summary>
        /// <returns>
        /// The session factory in an SQLite Memory Database.
        /// </returns>
        private static ISessionFactory CreateSessionFactory() {
            return FluentNHibernate.Cfg.Fluently.Configure()
            .Database(FluentNHibernate.Cfg.Db.SQLiteConfiguration
                .Standard
                .InMemory()
                .ShowSql())
            .Mappings(mappings => mappings.FluentMappings.AddFromAssemblyOf<Data.Mappings.AspectMap>())
            .ExposeConfiguration(configuration => Configuration = configuration)
            .BuildSessionFactory();
        }
        /// <summary>
        /// Builds the NHibernate Schema so that it can be mapped to the SessionFactory.
        /// </summary>
        /// <param name="Session">
        /// The <see cref="NHibernate.ISession"/> to build a schema into.
        /// </param>
        private static void BuildSchema(ISession Session) {
            var export = new NHibernate.Tool.hbm2ddl.SchemaExport(Configuration);
            export.Execute(true, true, false, Session.Connection, null);
        }
        /// <summary>
        /// Dispose of the session and released resources.
        /// </summary>
        public void Dispose() {
            Session.Dispose();
        }
    }
}

所以现在,为了使用它,我只是继承InMemoryDatabase并添加我的测试方法,就像这样。

[TestFixture]
    public class PersistenceTests : InMemoryDatabase {
        [Test]
        public void Save_Member() {
            var member = // ...;
            Session.Save(member); // not really how it looks, but you get the idea...
        }
    }

我的问题不是这不起作用。确实如此。但是,如果我在同一类中有两个测试来测试相似的数据,例如......

Username_Is_Unique()然后Email_Is_Unique().再次不是真正的测试,但这是一个很好的例子。

[Test]
public void Username_Is_Unique(){ 
   var user = new User { 
         Name = "uniqueName"
         Email = "uniqueEmail"
   };
   // do some testing here... 
}
[Test]
public void Email_Is_Unique(){ 
   var user = new User { 
         Name = "uniqueName"
         Email = "uniqueEmail"
   };
   // do some testing here... 
}

我意识到这些都是非常糟糕的测试。这些不是真正的测试,我只是举一个例子。

在这两种情况下,我都会构建一个模拟UserMember或你有什么,并将其提交给数据库。

第一个工作正常,但由于数据库在内存中(这是有道理的,因为我告诉它是(,第二个不能。实际上,单元测试并不反映现实世界的情况,因为每个测试都是独立的。但是当批量按顺序运行它们时,它的行为就像在现实世界中一样(我想这部分是一件好事(

我想做的是在每种方法之后刷新内存数据库。因此,我想出了一种通过重复构造函数来做到这一点的简单方法。这属于InMemoryDatabase类。

protected void Restart() {
            SessionFactory = CreateSessionFactory();
            Session = SessionFactory.OpenSession();
            BuildSchema(Session);
        }

所以现在,在我的继承类中的每个方法中,我在进行测试之前调用Restart()

我觉得这不是解决问题的预期或有效方法。谁能提出更好的解决方案?

如果它有任何相关性,我将Fluent nHibernate用于持久性,Telerik JustMock用于我的模拟 - 但对于我的数据库内容,我还没有需要任何模拟。

使用 Fluent nHibernate 进行单元测试 - 删除每个测试可能性的数据

您需要为每个测试删除并重新创建数据库。每个测试都应该相互独立。你可以做两件事,首先让你的测试使用设置方法(假设这里有NUnit,但其他人具有相同的功能(

    [SetUp]
    public void Setup()
    {
        // Create in memory database
        Memdb = new InMemoryDatabase();
    }

或者,可以将每个测试包装在数据库的 using 语句中。例如

[Test]
public void Test()
{
    using(var db = new InMemmoryDatabase())
    {
      Do Some Testing Here
    }
}