Log4net переинициализируется при каждом запуске теста, и каждый раз добавляются appender. Я подозреваю, что ReSharper не демонстрирует такое поведение, поскольку каждый раз запускает новый процесс (средство запуска тестов ReSharper), а графический интерфейс NUnit - нет.
В прошлом у меня были разные варианты этого, но довольно долго я использовал «SetupFixture» для инициализации log4net (среди прочего).
[SetUpFixture]
public class UnitTestSuiteSetupTeardown
{
[SetUp]
public void Setup()
{
log4net.Config.BasicConfigurator.Configure();
}
[TearDown]
public void Teardown()
{
//Teardown stuff...
}
}
Добавьте один из них на каждую тестовую сборку и убедитесь, что у класса нет пространства имен. Он будет запущен один раз для всех ваших тестов, то есть для всех тестов в сборке. Лично у меня есть один из них на уровне решения, а затем я добавляю его в качестве ссылки на каждый тестовый проект.
Обновление
Приведенный выше пример следует за вопросом и устанавливает базовую конфигурацию. В моей реальной SetUpFixture я инициализирую log4net из файла конфигурации log4net (который я снова сохраняю на уровне решения, а затем добавляю в качестве ссылки на все тестовые проекты), например,
[SetUpFixture]
public class UnitTestSuiteSetupTeardown
{
[SetUp]
public void Setup()
{
LogFactory.Configure();
}
[TearDown]
public void Teardown()
{
//Teardown stuff...
}
}
И пример класса типа LogFactory.
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();
}
}