I have this simple test:
protected readonly ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().ReflectedType);
private static int count = 0;
[Test]
public void TestConfiguredSuccessfully()
{
logger.Debug("开发者_如何学Cin test method" + count++);
}
log4net is set up like this:
[TestFixtureSetUp]
public void SetUp()
{
log4net.Config.BasicConfigurator.Configure();
}
The problem is, that if I run this test in nUnit once, I get the output (as expected):
1742 [TestRunnerThread] DEBUG Tests.TestSomthing (null) - in test method0
But if I press RUN in nUnit.exe again (or more) I get the following:
1742 [TestRunnerThread] DEBUG Tests.TestSomthing (null) - in test method1
1742 [TestRunnerThread] DEBUG Tests.TestSomthing (null) - in test method1
And so on (if I run it 5 times, I'll get 5 repeating lines). Now, if I run the same test alone from reSharper the output is fine and does not repeat. However, if I run this test along side 2 other tests in the same class, the output is repeated three times.
I am totally confused. What the hell is going on here?
Log4net is being re-initialized on each test run, and appender(s) added each time. I suspect that ReSharper does not exhibit the behaviour as it starts a new process each time (the ReSharper test runner) whereas the NUnit GUI does not.
I have had various flavours of this in the past, but for quite a while now I have used a "SetupFixture" to initialize log4net (amongst other things).
[SetUpFixture]
public class UnitTestSuiteSetupTeardown
{
[SetUp]
public void Setup()
{
log4net.Config.BasicConfigurator.Configure();
}
[TearDown]
public void Teardown()
{
//Teardown stuff...
}
}
Add one of these per test assembly, and ensure the class has no namespace. It will be run once for all of your tests i.e. all tests in the assembly. I personally have one of these at solution level and then add it in as a link to each test project.
Update
The example above follows the question and sets up basic configuration. In my actual SetUpFixture I initialize log4net from a log4net configuration file (which I again store at solution level and then add as a link to all test projects), e.g.
[SetUpFixture]
public class UnitTestSuiteSetupTeardown
{
[SetUp]
public void Setup()
{
LogFactory.Configure();
}
[TearDown]
public void Teardown()
{
//Teardown stuff...
}
}
And a sample LogFactory type class.
public static class LogFactory
{
public const string DefaultConfigFileName = "log4net.config";
static ILog GetLogger(Type callingType)
{
return new Log4NetLogger(LogManager.GetLogger(callingType));
}
public static void Configure()
{
Type type = typeof(LogFactory);
FileInfo assemblyDirectory = AssemblyInfo.GetCodeBaseDirectory(type);
FileInfo configFile = new FileInfo(Path.Combine(assemblyDirectory.FullName,
DefaultConfigFileName));
XmlConfigurator.ConfigureAndWatch(configFile);
log4net.ILog log = LogManager.GetLogger(type);
log.ToString();
}
}
精彩评论