2009-03-27 4 views
2

Contexte:Utilisation de MbUnit3 de [Rollback] pour les interactions NHibernate de tests unitaires avec SQLite

Mon équipe se consacre à faire en sorte que, notre code compile et tests unitaires exécuté avec succès directement à partir de la caisse. Pour faciliter cela et tester certains de nos mappages NHibernate, nous avons ajouté une base de données SQLite à notre référentiel qui est un miroir de notre base de données de production SQL Server 2005. Nous utilisons les dernières versions de: MbUnit3 (partie de Gallio), System.Data.SQLite et NHibernate.

Problème:

J'ai découvert que le test unitaire suivant ne fonctionne pas avec SQLite, en dépit de l'exécution sans problème contre 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)); 
    } 

L'exception que je reçois (SEULEMENT lorsque vous travaillez avec SQLite) suit:

 
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 

lorsque SQLite est utilisé et l'attribut [Rollback] n'est pas spe cified, le test se termine également avec succès.

Question:

Est-ce un problème avec la mise en œuvre de System.Data.SQLite de TransactionScope qui utilise MbUnit3 pour [Rollback] ou une limitation du moteur SQLite?

Existe-t-il un moyen d'écrire ce test unitaire, en utilisant SQLite, qui sera annulé afin d'éviter d'affecter la base de données à chaque fois que le test est exécuté?

Répondre

1

Vérifiez si vous ne manquez pas connection.release_mode=on_close dans votre configuration SQLite NHibernate. (reference docs)

BTW: toujours disposer de ISession et ISessionFactory.

+0

Bon appel - J'avais vu cette partie du document il y a quelques jours mais cela ne me semblait pas être le problème que j'observais maintenant. La modification de ma version de release_mode a corrigé les tests. Merci! – antik

0

Ditch [Rollback] et utilisez NDbUnit. Je l'utilise moi-même pour ce scénario précis et cela fonctionne très bien.

+0

NDbUnit.org est en baisse depuis la mi-février lorsque nous avons sélectionné des cadres. Ma plus grande plainte à propos de Gallio est son manque de documentation et à moins qu'il y ait de la documentation quelque part que je ne vois pas, c'est un pas en arrière même d'où je suis maintenant. – antik

+0

Oui, NDbUnit est inactif depuis longtemps, bien qu'il y ait eu une activité récente sur le site de code google. * hausser les épaules * Je suis passé par le même combat avec MbUnit/Gallio et je n'ai jamais réussi à le faire fonctionner correctement. J'espère que quelqu'un d'autre peut nous montrer la lumière :) – remotefacade

2

Ce n'est pas une vraie réponse à votre question, mais probablement une solution pour résoudre le problème. J'utilise une implémentation en mémoire de sql lite pour mes tests d'intégration. Je construis le schéma et remplis la base de données avant chaque test. La création du schéma et le remplissage initial des données sont très rapides (moins de 0,01 seconde par test) car il s'agit d'une base de données en mémoire.

Pourquoi utilisez-vous une base de données physique?

Edit: réponse à répondre au sujet de la question ci-dessus:

1.) Parce que je migré mon schéma et les données directement à partir de SQL Server 2005 et je veux qu'il persiste dans le contrôle source.

  • Je recommande de stocker un fichier avec le schéma de base de données et un fichier ou un script qui crée les données d'exemple dans le contrôle de source. Vous pouvez générer le fichier en utilisant sql server studion management express, vous pouvez le générer à partir de vos mappings NHibernate ou vous pouvez utiliser un outil comme sql compare et vous pouvez probablement trouver d'autres solutions pour cela quand vous en avez besoin. Les fichiers texte brut sont stockés plus facilement dans les systèmes de contrôle de version, puis complètent les fichiers de base de données binaires. 2) Est-ce que quelque chose à propos du moteur SQLite en mémoire diffère de sorte qu'il résoudrait cette difficulté?Il peut résoudre vos problèmes car vous pouvez recréer votre base de données avant chaque test. Votre base de données en cours de test sera dans l'état que vous attendez avant chaque test. Un avantage de cela est qu'il n'y a pas besoin d'annuler vos transactions, mais j'ai exécuté un test similaire avec sqllite dans la mémoire et cela a fonctionné comme aspecté.
+0

Parce que j'ai migré mon schéma et les données directement à partir de SQL Server 2005 et je veux qu'il persiste dans le contrôle de la source. Est-ce que quelque chose sur le moteur SQLite en mémoire diffère de sorte qu'il résoudrait cette difficulté? – antik

+0

Paco - Quelle base de données SQL en mémoire avez-vous utilisée? Je pense que c'est certainement une option qui mérite d'être étudiée. –

+0

@Burly: Sql-lite peut fonctionner en mémoire – Paco

Questions connexes