代码之家  ›  专栏  ›  技术社区  ›  Egor Pavlikhin

多次记录(或运行)单元测试

  •  9
  • Egor Pavlikhin  · 技术社区  · 15 年前

    我有一个简单的测试:

    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 in 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 回复  |  直到 14 年前
        1
  •  7
  •   Tim Lloyd    15 年前

    log4net在每次测试运行时都被重新初始化,并且每次都添加了附加器。我怀疑resharper在每次启动新进程(resharper测试运行程序)时不会表现出这种行为,而nunit GUI则不会。

    在过去,我有过各种各样的味道,但是有一段时间,我使用了一个“安装夹具”来初始化log4net(以及其他东西)。

    [SetUpFixture]
    public class UnitTestSuiteSetupTeardown
    {
        [SetUp]
        public void Setup()
        {
            log4net.Config.BasicConfigurator.Configure();
        }
    
        [TearDown]
        public void Teardown()
        {
            //Teardown stuff...
        }
    }
    

    为每个测试程序集添加其中一个,并确保类没有命名空间。它将为所有测试(即程序集中的所有测试)运行一次。我个人在解决方案级别拥有其中一个,然后将其作为链接添加到每个测试项目中。

    更新

    上面的示例遵循问题并设置基本配置。在我的实际安装夹具中,我从一个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();
        }
    }