我想知道在NUnit项目中初始化log4Net的最佳方法是什么。当然我想尽快调用init代码(即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()
并禁止使用任何静态初始化程序?那是艰苦的工作!
有人知道一个神奇的伎俩吗?
答案 0 :(得分:4)
对于单个初始化点,您应该使用标有[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
将在SetUp
TestsInitializer
后运行,但VeryComplexLogicTests
可能会以随机顺序运行。
根据linked documentation,如果您在任何命名空间之外声明SetUpFixture
类,则setup和teardown将适用于整个程序集:
在给定的命名空间中只应创建一个SetUpFixture。任何命名空间之外的SetUpFixture为整个程序集提供SetUp和TearDown。
答案 1 :(得分:1)
一位工作伙伴为我提供了以下解决方法:完成工作:
在我需要记录的所有类中,我进行了以下记录器初始化
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必须尽早调用这个静态初始化程序来实例化我的测试类。
下一步是使该线程安全:(