Модульное тестирование с помощью Fluent nHibernate - удаление данных для каждой возможности тестирования - PullRequest
0 голосов
/ 21 июня 2011

Я настроил несколько модульных тестов SQLite в памяти для своей базы данных Fluent NHibernate, которая выглядит следующим образом. Работает нормально. (С использованием 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 и добавляю свои методы Test, вот так.

[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... 
}

Я понимаю, что это очень плохие тесты. Это не настоящие тесты, я просто привожу пример.

В обоих случаях я бы создал макет User или Member или что-то еще и отправил бы его в базу данных.

Первый работает нормально, но, поскольку база данных находится в памяти (что имеет смысл, поскольку я это сказал), вторая - нет. По сути, модульные тесты не отражают реальных ситуаций, потому что каждый тест стоит сам по себе. Но когда они запускаются последовательно в пакете, он ведет себя так, как должен в реальном мире (я полагаю, это отчасти хорошо)

Что я хочу сделать, это очистить базу данных в памяти после каждого метода. Поэтому я придумал простой способ сделать это, повторив конструктор. Это относится к классу InMemoryDatabase.

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

Итак, теперь в каждом методе моего класса наследования я вызываю Restart() перед тем, как приступить к тестированию.

Я чувствую, что это не намеченный или эффективный способ решения моей проблемы. Кто-нибудь может предложить лучшее решение?

Если это имеет какое-либо отношение, я использую Fluent nHibernate для постоянства и Telerik JustMock для моего Пересмешивания - но для моей базы данных мне еще не нужно насмехаться.

1 Ответ

1 голос
/ 21 июня 2011

Вам нужно удалить и воссоздать базу данных для каждого теста.Каждый тест должен быть независимым от другого.Вы можете сделать две вещи, во-первых, чтобы ваш тест использовал метод настройки (при условии, что здесь есть 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
    }
}
...