使用NUnit尽早初始化log4Net
我想知道在NUnit项目中初始化log4Net的最佳方法是什么。 当然我想尽快调用init代码(即XmlConfigurator.Configure()
)来获取尽可能多的早期日志输出。 但由于我的项目是通过NUnit运行的,因此我对其入口点几乎无法控制。
根据NUnit文档,它应首先调用一些构造函数,然后在标有[TestFixtureSetup]
的类中使用[TestFixtureSetup]
[SetUp]
属性标记的方法。
所以,首先,我创建了一个静态助手类,我可以多次调用它而不会出现问题。
public static class LoggingFacility { private static bool _loggerIsUp = false; public static void InitLogger() { if (_loggerIsUp == false) XmlConfigurator.ConfigureAndWatch(f); _loggerIsUp = true; } }
然后,我使所有[TestFixtureSetup]
inheritance了一个除了调用LoggingFacility.initLogger()
之外几乎没有的东西。 但是,这仍然会使所有早期运行的构造函数按照我只能随机假设的顺序运行。 而且,在我甚至无法执行某些代码之前,它可能会进行一些静态初始化。
事实上,正如我在日志中看到的那样,执行的前4秒左右完全没有记录。
这是否意味着我必须在每个构造函数中调用我的InitLogger()
并禁止使用任何静态初始化程序? 那是艰苦的工作!
有人知道这个魔术吗?
对于单个初始化点,您应该使用标有[SetUpFixture]
属性的类和使用[SetUp]
标记的方法,例如:
[SetUpFixture] public class TestsInitializer { [SetUp] public void InitializeLogger() { LoggingFacility.InitLogger(); } }
现在,这个方法( [SetUp] InitializeLogger
)将在任何测试运行之前运行,与运行所有测试后运行的[TearDown]
标记的测试相同。 但这里有一个问题 – 在这种情况下, 任何和所有意味着什么? 在与使用[SetUpFixture]
标记的类相同的命名空间中声明的类中进行测试。
例如,假设层次结构如下:
- Tests --- Business ----- TestsInitializer.cs // SetUpFixture class ----- FirstBusinessTests.cs ----- SecondBusinesTests.cs --- ComplexLogic ----- VeryComplexLogicTests.cs
First
和SecondBusinessTests
将在 TestsInitializer
SetUp
之后运行,但VeryComplexLogicTests
可能以随机顺序运行。
根据链接文档 ,如果在任何命名空间之外声明SetUpFixture
类,则setup和teardown将适用于整个程序集:
在给定的命名空间中只应创建一个SetUpFixture。 任何命名空间之外的SetUpFixture为整个程序集提供SetUp和TearDown。
工作伙伴为我提供了以下解决方法:
在我需要记录的所有类中,我进行了以下记录器初始化
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必须尽早调用这个静态初始化程序来实例化我的测试类。
下一步是使该线程安全:(