2010-04-22 13 views
8

Dans certains tests unitaires/d'intégration du code, nous souhaitons vérifier que l'utilisation correcte du cache de second niveau est utilisée par notre code.Nombre de requêtes exécutées par NHibernate dans un test unitaire

Basé sur le code présenté par Ayende ici:

http://ayende.com/Blog/archive/2006/09/07/MeasuringNHibernatesQueriesPerPage.aspx

j'ai écrit une classe simple pour faire cela:

public class QueryCounter : IDisposable 
{ 
    CountToContextItemsAppender _appender; 

    public int QueryCount 
    { 
     get { return _appender.Count; } 
    } 

    public void Dispose() 
    { 
     var logger = (Logger) LogManager.GetLogger("NHibernate.SQL").Logger; 
     logger.RemoveAppender(_appender); 
    } 

    public static QueryCounter Start() 
    { 
     var logger = (Logger) LogManager.GetLogger("NHibernate.SQL").Logger; 

     lock (logger) 
     { 
     foreach (IAppender existingAppender in logger.Appenders) 
     { 
      if (existingAppender is CountToContextItemsAppender) 
      { 
      var countAppender = (CountToContextItemsAppender) existingAppender; 

      countAppender.Reset(); 

      return new QueryCounter {_appender = (CountToContextItemsAppender) existingAppender}; 
      } 
     } 

     var newAppender = new CountToContextItemsAppender(); 
     logger.AddAppender(newAppender); 
     logger.Level = Level.Debug; 
     logger.Additivity = false; 

     return new QueryCounter {_appender = newAppender}; 
     } 
    } 

    public class CountToContextItemsAppender : IAppender 
    { 
     int _count; 

     public int Count 
     { 
     get { return _count; } 
     } 

     public void Close() 
     { 
     } 

     public void DoAppend(LoggingEvent loggingEvent) 
     { 
     if (string.Empty.Equals(loggingEvent.MessageObject)) return; 
     _count++; 
     } 

     public string Name { get; set; } 

     public void Reset() 
     { 
     _count = 0; 
     } 
    } 
} 

Avec l'usage prévu:

using (var counter = QueryCounter.Start()) 
{ 
    // ... do something 
    Assert.Equal(1, counter.QueryCount); // check the query count matches our expectations 
} 

Mais il renvoie toujours 0 pour le nombre de requêtes. Aucune instruction SQL n'est en cours de journalisation.

Toutefois, si je utilise Nhibernate Profiler et invoquez dans mon cas test:

NHibernateProfiler.Intialize() 

Où NHProf utilise une approche similaire pour capturer la sortie de l'enregistrement de NHibernate pour l'analyse par log4net etc. alors mon QueryCounter commence à travailler . Il semble qu'il me manque quelque chose dans mon code pour que log4net soit correctement configuré pour la journalisation de nhibernate sql ... Quelqu'un a-t-il des pointeurs sur ce que je dois faire pour obtenir la sortie de journalisation sql de Nhibernate?

Informations complémentaires:

logging.config:

<log4net> 

    <appender name="trace" type="log4net.Appender.TraceAppender, log4net"> 
    <layout type="log4net.Layout.PatternLayout,log4net"> 
     <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] &amp;lt;%P{user}&amp;gt; - %m%n" /> 
    </layout> 
    </appender> 

    <appender name="console" type="log4net.Appender.ConsoleAppender, log4net"> 
    <layout type="log4net.Layout.PatternLayout,log4net"> 
     <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] &amp;lt;%P{user}&amp;gt; - %m%n" /> 
    </layout> 
    </appender> 

    <appender name="debug" type="log4net.Appender.DebugAppender, log4net"> 
    <layout type="log4net.Layout.PatternLayout,log4net"> 
     <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] &amp;lt;%P{user}&amp;gt; - %m%n" /> 
    </layout> 
    </appender> 

    <logger name="NHibernate.SQL" additivity="false"> 
    <level value="DEBUG" /> 
    <appender-ref ref="ConsoleAppender" /> 
    </logger> 

    <root> 
    <priority value="DEBUG" /> 
    <appender-ref ref="trace" /> 
    <appender-ref ref="console" /> 
    <appender-ref ref="debug" /> 
    </root> 

</log4net> 

show_sql: true

Sur la base de jfneis réponse, je l'ai écrit une classe beaucoup plus simple qui utilise simplement les statistiques de l'usine de NHibernate:

public class QueryCounter 
{ 
    long _startCount; 

    QueryCounter() 
    { 
    } 

    public int QueryCount 
    { 
    get { return (int) (UnitOfWork.CurrentSession.SessionFactory.Statistics.QueryExecutionCount - _startCount); } 
    } 

    public static QueryCounter Start() 
    { 
    return new QueryCounter {_startCount = UnitOfWork.CurrentSession.SessionFactory.Statistics.QueryExecutionCount}; 
    } 
} 

Ce qui fonctionne très bien une fois les statistiques activées.

+0

Bittercoder, je suis sur ma machine dev en ce moment donc je ne peux pas poster code, mais avez-vous essayé d'utiliser des statistiques pour le faire? J'ai également fait face à ce genre de problème pour tester L2 et les statistiques où assez à mon scénario. Retour au bureau (12h à partir de maintenant) Je posterai (si nécessaire) une réponse complète. J'espère que cela aide jusqu'à là. – jfneis

+0

Dans votre configuration nhibernate avez-vous défini show_sql sur true? Pouvez-vous également poster votre fichier log4net.config? – mhanney

+0

Oui, essayé avec show_sql mis à vrai et faux. Bien que je pensais que show_sql n'utilisait pas log4net et juste jeté les instructions SQL à stdout? J'ai maintenant inclus ma configuration log4net dans la question initiale. Le fait que NHibernateProfiler.Initialize() fasse ensuite fonctionner ma classe me suggère que c'est probablement une configuration log4net programmatique qui me manque. – Bittercoder

Répondre

13

Il existe un autre moyen (plus simple, IMO) d'affirmer si le cache est en cours d'exécution ou si des requêtes sont en cours d'exécution: utilisation de statistiques.

Tout d'abord, vous devez activer les statistiques dans votre fichier de configuration NH:

<property name="generate_statistics">true</property> 

Après cela, vous pouvez demander à votre usine de session chaque fois que vous voulez comment les choses vont. Vous avez parlé des tests de cache L2, de sorte que vous pourriez avoir quelque chose comme ça:

 // act 
     MappedEntity retrievedEntity = session.FindById(entity.Id); 
     long preCacheCount = sessionFactory.Statistics.SecondLevelCacheHitCount; 
     retrievedEntity = session.FindById(entity.Id); 
     long postCacheCount = sessionFactory.Statistics.SecondLevelCacheHitCount; 
     // assert 
     Assert.AreEqual(preCacheCount + 1, postCacheCount); 

Mais, si ce que vous voulez vraiment est le nombre de requêtes, il y a beaucoup d'autres options dans l'interface Statistiques:

 sessionFactory.Statistics.QueryExecutionCount; 
     sessionFactory.Statistics.TransactionCount; 

Eh bien, c'est tout. J'espère que cela vous aide comme m'a aidé.

Cordialement,

Filipe

+0

J'ai donné un coup d'oeil aux statistiques, et je n'ai trouvé aucune statistique de requête - mais j'ai regardé ISessionStatistics, ISessionFactory.Statistics (IStatistics). Je vais y aller :) – Bittercoder

+0

Implémenté classe simple en utilisant les statistiques - fonctionne très bien - merci pour l'aide José! – Bittercoder

+0

Je suis content de savoir que ça t'a aidé. – jfneis