Инициализируйте log4Net как можно раньше с помощью NUnit - PullRequest
2 голосов
/ 08 марта 2012

Мне интересно, как лучше всего инициализировать log4Net в проекте NUnit. Конечно, я хочу вызвать код инициализации (т. Е. XmlConfigurator.Configure()), как только смогу, чтобы получить как можно больше ранних выходных данных журнала. Но так как мой проект выполняется через NUnit, у меня мало контроля над точкой входа.

Согласно документации NUnit, он должен сначала вызывать некоторые конструкторы, затем метод, отмеченный атрибутом [SetUp] в классе, отмеченном [TestFixtureSetup].

Итак, во-первых, я создал статический вспомогательный класс, который я могу вызывать несколько раз без проблем.

  public static class LoggingFacility
  {
    private static bool _loggerIsUp = false;

    public static void InitLogger()
    {
      if (_loggerIsUp == false)
        XmlConfigurator.ConfigureAndWatch(f);

      _loggerIsUp = true;
    }
  }

Затем я заставил все мои [TestFixtureSetup] наследовать один, который почти ничего не делает, кроме вызова LoggingFacility.initLogger(). Но это все же оставляет все конструкторы, которые запускаются ранее, в порядке, который я могу принять только случайным. Более того, он, вероятно, выполнит некоторые статические инициализации, прежде чем я смогу выполнить какой-то код.

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

Значит ли это, что мне придется вызывать мой InitLogger() в каждом конструкторе и запретить использование какого-либо статического инициализатора? Это тяжелая работа!

Кто-нибудь знает магический трюк с этим?

Ответы [ 2 ]

4 голосов
/ 08 марта 2012

Для отдельной точки инициализации вы должны использовать класс, помеченный [SetUpFixture], атрибут и метод, помеченный [SetUp], например:

[SetUpFixture]
public class TestsInitializer
{
    [SetUp]
    public void InitializeLogger()
    {
        LoggingFacility.InitLogger();
    }
}

Теперь этот метод ([SetUp] InitializeLogger) будет запускаться до запуска любого теста , так же, как и тот, который помечен [TearDown], будет запускаться после запуска всех тестов.Но здесь есть одна загвоздка - что any и all означает в этом контексте?Тесты из классов , объявленных в том же пространстве имен, что и класс, помеченный [SetUpFixture].

Например, предполагая иерархию, подобную этой:

- Tests
--- Business
----- TestsInitializer.cs // SetUpFixture class
----- FirstBusinessTests.cs
----- SecondBusinesTests.cs
--- ComplexLogic
----- VeryComplexLogicTests.cs

First и SecondBusinessTests будут работать после SetUp с TestsInitializer, однако VeryComplexLogicTests может работать в произвольном порядке.

Согласно связанной документации , если вы объявите класс SetUpFixture вне какого-либо пространства имен, настройка и разбор будут применяться для всей сборки:

В данном пространстве имен должен быть создан только один SetUpFixture.SetUpFixture вне любого пространства имен обеспечивает SetUp и TearDown для всей сборки.

1 голос
/ 12 марта 2012

Сотрудник предоставил мне следующий обходной путь, который выполняет эту работу:

Во всех моих классах, требующих регистрации, у меня была следующая инициализация регистратора

private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

Я просто изменилэто одноэлементному инициализатору

private static readonly ILog Log = LoggingFacility.GetLoggerWithInit(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

/*** ... ***/

public static class LoggingFacility
{
  private static bool _loggerIsUp = false;

  public static ILog GetLoggerWithInit(Type declaringType)
  {
    if (_loggerIsUp == false)
      XmlConfigurator.Configure(_log4NetCfgFile);
    _loggerIsUp = true;
    return LogManager.GetLogger(declaringType);
  }
}

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

...