Pergunta

Estou me perguntando qual é a melhor maneira de inicializar o log4Net em um projeto NUnit.Claro que quero chamar o código init (ou seja. XmlConfigurator.Configure()) assim que puder para obter o máximo possível de saídas de log antecipadas.Mas como meu projeto é executado no NUnit, tenho pouco controle sobre seu ponto de entrada.

De acordo com a documentação do NUnit, ele deve chamar primeiro alguns construtores e depois um método marcado com o [SetUp] atributo em uma classe marcada com [TestFixtureSetup].

Então, primeiro, criei uma classe auxiliar estática que posso chamar várias vezes sem problemas.

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

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

      _loggerIsUp = true;
    }
  }

Então, fiz todos os meus [TestFixtureSetup] herdar um único que não faz praticamente nada além de ligar LoggingFacility.initLogger().Mas isso ainda deixa todos os construtores executados anteriormente, em uma ordem que só posso assumir aleatória.Além disso, provavelmente fará algumas inicializações estáticas antes mesmo de eu conseguir executar algum código.

Na verdade, como posso ver em meu log, os primeiros 4 segundos de execução não são registrados.

Isso significa que terei que ligar para meu InitLogger() em todos os construtores e proíbe o uso de qualquer inicializador estático?Esse é um trabalho difícil!

Alguém conhece um truque de mágica com isso?

Foi útil?

Solução 2

Um colega de trabalho me forneceu a seguinte solução alternativa, que funciona:

Em todas as minhas aulas que exigem log, tive a seguinte inicialização do logger

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

Eu simplesmente mudei para um inicializador singleton

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

Como tenho esse código em todas as classes, esse inicializador estático deve ser chamado muito cedo pelo NUnit enquanto instancia minhas classes de teste.

O próximo passo é tornar esse thread seguro :(

Outras dicas

Para um único ponto de inicialização você deve usar a classe marcada com [SetUpFixture] atributo e método marcados com [SetUp], por exemplo:

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

Agora, este método ([SetUp] InitializeLogger) correrá antes de qualquer teste é executado, igual ao marcado com [TearDown] será executado assim que todos os testes forem executados.Mas aqui está o problema - o que significa qualquer e todos significa neste contexto?Testes das aulas declarado no mesmo namespace da classe marcada com [SetUpFixture].

Por exemplo, assumindo uma hierarquia como esta:

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

First e SecondBusinessTests correrá depois SetUp de TestsInitializer, no entanto VeryComplexLogicTests pode ser executado em ordem aleatória.

De acordo com documentação vinculada, se você declarar SetUpFixture classe fora de qualquer namespace, a configuração e a desmontagem serão aplicadas a toda a montagem:

Apenas um SetUpFixture deve ser criado em um determinado namespace.Um SetUpFixture fora de qualquer namespace fornece SetUp e TearDown para toda a montagem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top