Модульные тесты регистрируются (или запускаются) несколько раз - PullRequest
9 голосов
/ 15 июня 2010

У меня есть этот простой тест:

protected readonly ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().ReflectedType);
private static int count = 0;
[Test]
public void TestConfiguredSuccessfully()
{
    logger.Debug("in test method" + count++);
}

log4net настроен так:

[TestFixtureSetUp]
public void SetUp()
{
    log4net.Config.BasicConfigurator.Configure();
}

Проблема в том, что, если я запускаю этот тест в nUnit один раз, я получаювывод (как и ожидалось):

1742 [TestRunnerThread] DEBUG Tests.TestSomthing (null) - in test method0

Но если я снова нажму на RUN в nUnit.exe (или больше), я получу следующее:

1742 [TestRunnerThread] DEBUG Tests.TestSomthing (null) - in test method1
1742 [TestRunnerThread] DEBUG Tests.TestSomthing (null) - in test method1

И так далее (если язапусти 5 раз, я получу 5 повторяющихся строк).Теперь, если я запускаю один и тот же тест из reSharper, вывод в порядке и не повторяется.Однако, если я проведу этот тест вместе со стороной 2 других тестов в том же классе, вывод будет повторен три раза.

Я полностью сбит с толку.Что, черт возьми, здесь происходит?

1 Ответ

7 голосов
/ 15 июня 2010

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