Использование MbUnit3 [Rollback] для модульного тестирования взаимодействия NHibernate с SQLite

StackOverflow https://stackoverflow.com/questions/691151

Вопрос

Предыстория:

Моя команда стремится к тому, чтобы сразу после оформления заказа наш код компилировался и модульные тесты выполнялись успешно.Чтобы облегчить это и протестировать некоторые из наших сопоставлений NHibernate, мы добавили базу данных SQLite в наш репозиторий, который является зеркалом нашей производственной базы данных SQL Server 2005.Мы используем последние версии:MbUnit3 (часть Gallio), System.Data.SQLite и NHibernate.

Проблема:

Я обнаружил, что следующий модульный тест не работает с SQLite, несмотря на то, что выполняется без проблем с SQL Server 2005.

    [Test]
    [Rollback]
    public void CompleteCanPersistNode()
    {
        // returns a Configuration for either SQLite or SQL Server 2005 depending on how the project is configured.
        Configuration config = GetDbConfig(); 

        ISessionFactory sessionFactory = config.BuildSessionFactory();
        ISession session = sessionFactory.OpenSession();

        Node node = new Node();
        node.Name = "Test Node";
        node.PhysicalNodeType = session.Get<NodeType>(1);

        // SQLite fails with the exception below after the next line called.
        node.NodeLocation = session.Get<NodeLocation>(2);

        session.Save(node);
        session.Flush();

        Assert.AreNotEqual(-1, node.NodeID);
        Assert.IsNotNull(session.Get<Node>(node.NodeID));
    }

Исключение, которое я получаю (ТОЛЬКО при работе с SQLite), следует:

NHibernate.ADOException: cannot open connection --->
System.Data.SQLite.SQLiteException:
  The database file is locked database is locked
    at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt)
    at System.Data.SQLite.SQLiteDataReader.NextResult()
    at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
    at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
    at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
    at System.Data.SQLite.SQLiteTransaction..ctor(SQLiteConnection connection, Boolean deferredLock)
    at System.Data.SQLite.SQLiteConnection.BeginDbTransaction(IsolationLevel isolationLevel)
    at System.Data.SQLite.SQLiteConnection.BeginTransaction()
    at System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn, Transaction scope)
    at System.Data.SQLite.SQLiteConnection.EnlistTransaction(Transaction transaction)
    at System.Data.SQLite.SQLiteConnection.Open()
    at NHibernate.Connection.DriverConnectionProvider.GetConnection()
    at NHibernate.Impl.SessionFactoryImpl.OpenConnection()
    --- End of inner exception stack trace ---
    at NHibernate.Impl.SessionFactoryImpl.OpenConnection()
    at NHibernate.AdoNet.ConnectionManager.GetConnection()
    at NHibernate.AdoNet.AbstractBatcher.Prepare(IDbCommand cmd)
    at NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand cmd)
    at NHibernate.Loader.Loader.GetResultSet(IDbCommand st, Boolean autoDiscoverTypes, Boolean callable, RowSelection selection, ISessionImplementor session)
    at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
    at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
    at NHibernate.Loader.Loader.LoadEntity(ISessionImplementor session, Object id, IType identifierType, Object optionalObject, String optionalEntityName, Object optionalIdentifier, IEntityPersister persister)
    at NHibernate.Loader.Entity.AbstractEntityLoader.Load(ISessionImplementor session, Object id, Object optionalObject, Object optionalId)
    at NHibernate.Loader.Entity.AbstractEntityLoader.Load(Object id, Object optionalObject, ISessionImplementor session)
    at NHibernate.Persister.Entity.AbstractEntityPersister.Load(Object id, Object optionalObject, LockMode lockMode, ISessionImplementor session)
    at NHibernate.Event.Default.DefaultLoadEventListener.LoadFromDatasource(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
    at NHibernate.Event.Default.DefaultLoadEventListener.DoLoad(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
    at NHibernate.Event.Default.DefaultLoadEventListener.Load(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
    at NHibernate.Event.Default.DefaultLoadEventListener.ProxyOrLoad(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
    at NHibernate.Event.Default.DefaultLoadEventListener.OnLoad(LoadEvent event, LoadType loadType)
    at NHibernate.Impl.SessionImpl.FireLoad(LoadEvent event, LoadType loadType)
    at NHibernate.Impl.SessionImpl.Get(String entityName, Object id)
    at NHibernate.Impl.SessionImpl.Get(Type entityClass, Object id)
    at NHibernate.Impl.SessionImpl.Get[T](Object id)
D:\dev\598\Code\test\unit\DataAccess.Test\NHibernatePersistenceTests.cs

Когда используется SQLite и атрибут [Rollback] НЕ указан, тест также успешно завершается.

Вопрос:

Является ли это проблемой с реализацией System.Data.SQLite TransactionScope, которую MbUnit3 использует для [Отката], или ограничением движка SQLite?

Есть ли какой-нибудь способ написать этот модульный тест, работающий против SQLite, который будет выполнять откат, чтобы избежать воздействия на базу данных при каждом запуске теста?

Это было полезно?

Решение

Проверьте, не пропали ли вы без вести connection.release_mode=on_close в вашей конфигурации SQLite NHibernate.(справочные документы)

КСТАТИ:всегда распоряжайтесь своим ISession и ISessionFactory.

Другие советы

Это не реальный ответ на ваш вопрос, но, вероятно, решение для решения проблемы.

Я использую встроенную в память реализацию sql lite для своих интеграционных тестов.Я создаю схему и заполняю базу данных перед каждым тестированием.Создание схемы и начальное заполнение данных происходит очень быстро (менее 0,01 секунды за тест), потому что это база данных в памяти.

Почему вы используете физическую базу данных?

Редактировать:ответ на ответ о вопросе выше:

1.) Потому что я перенес свою схему и данные непосредственно с SQL Server 2005 и хочу, чтобы они сохранялись в системе управления версиями.

  • Я рекомендую сохранить файл со схемой базы данных и файл или скрипт, который создает образцы данных в системе управления версиями.Вы можете сгенерировать файл с помощью sql server studion management express, вы можете сгенерировать его на основе ваших сопоставлений NHibernate или вы можете использовать такой инструмент, как sql compare, и, вероятно, вы сможете найти другие решения для этого, когда вам это понадобится.Обычные текстовые файлы проще хранить в системах контроля версий, чем полные двоичные файлы базы данных.

2.) Отличается ли что-то в движке SQLite в памяти настолько, что это решило бы эту трудность?

  • Это может решить ваши проблемы, потому что вы можете воссоздавать свою базу данных перед каждым тестированием.Ваша тестируемая база данных будет находиться в том состоянии, в котором вы ожидаете ее видеть перед выполнением каждого теста.Преимущество этого в том, что нет необходимости откатывать ваши транзакции, но я запустил аналогичный тест с in memory sqllite, и он сработал как положено.

Отбросить [Откат] и использовать Модуль поиска.Я сам использую это именно для этого сценария, и это отлично работает.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top