2010-04-22 3 views
8

В некоторых тестах на единицу/интеграции кода мы хотим проверить правильность использования кеша второго уровня нашим кодом.Подсчитайте количество запросов, выполненных NHibernate в единичном тесте

на основе кода, представленного Ayende здесь:

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

Я написал простой класс для выполнения только что:

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; 
     } 
    } 
} 

С предполагаемого использования:

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

Но он всегда возвращает 0 для подсчета запросов. Записи sql не регистрируются.

Однако, если я использую NHibernate Profiler и вызвать это в моем тесте:

NHibernateProfiler.Intialize() 

Где NHProf использует подобный подход для записи выходных данных каротажа с NHibernate для анализа с помощью log4net и т.д., то мой QueryCounter начала работы ,

Похоже, что в моем коде отсутствует что-то, чтобы правильно настроить log4net для регистрации nhibernate sql ... есть ли у кого-нибудь какие-либо указатели на то, что еще мне нужно сделать, чтобы получить вывод sql-журнала из Nhibernate?

Дополнительная информация:

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: истинный

основы jfneis ответа я написал гораздо более простой класс, который просто использует фабричную статистику 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}; 
    } 
} 

Который работает просто отлично, когда статистика включена.

+0

Bittercoder, я из моего Dev машины прямо сейчас, так я не могу отправить код, но вы пытались использовать статистику, чтобы сделать это? Я также столкнулся с такой проблемой, чтобы проверить L2 и Statistics, где достаточно моего сценария. Вернувшись в офис (12 часов), я отправлю (если нужно) полный ответ. Надеюсь, это поможет, пока не появится. – jfneis

+0

В вашей конфигурации nhibernate вы установили show_sql в true? Вы также можете опубликовать свой журнал log4net.config? – mhanney

+0

Да, попробовал с show_sql установить true и false. Хотя я думал, что show_sql не использует log4net и просто выкидывает sql-команды в stdout? Теперь я включил конфигурацию log4net в начальный вопрос. Тот факт, что NHibernateProfiler.Initialize() затем вызывает работу моего класса, подсказывает мне, что это, вероятно, некоторая программная конфигурация log4net, которую я пропускаю. – Bittercoder

ответ

13

Существует еще один (более простой, ИМО) способ утверждения, если кэш попал или выполняются запросы: с использованием статистики.

Прежде всего, вы должны включить статистику в вашем файле конфигурации NH:

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

После этого, вы можете попросить вашего сеанса завода всякий раз, когда вы хотите, как обстоят дела. Вы говорили о тестировании кэша L2, так что вы могли бы иметь что-то вроде этого:

 // 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); 

Но, если то, что вы действительно хотите это счетчик запросов, есть много других вариантов в интерфейсе статистики:

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

Ну, вот и все. Надеюсь, это поможет вам, как помогло мне.

С уважением,

Filipe

+0

Я посмотрел статистику и не нашел статистики запросов, но я смотрел ISessionStatistics, ISessionFactory.Statistics (IStatistics). Дайте ему пойти :) – Bittercoder

+0

Реализованный простой класс с использованием статистики - отлично работает - спасибо за помощь José! – Bittercoder

+0

Я рад узнать, что это вам помогло. – jfneis