【问题标题】:Unit Test & Log4net单元测试和 Log4net
【发布时间】:2011-11-17 06:17:23
【问题描述】:

我在我的控制器中对一个动作进行单元测试,该动作写入 log4net。

当我运行我的操作时,它运行良好 - 写入 log4net。

但是,当我运行单元测试时 - 该操作不会写入 log4net 但不会引发任何异常。

有人有解决办法吗?

【问题讨论】:

  • 只是猜测,但您是否在 app.config 文件中为您的单元测试项目添加了必要的 log4net 配置信息?

标签: asp.net asp.net-mvc-3 unit-testing


【解决方案1】:
// ARRANGE
var memoryAppender = new MemoryAppender();
BasicConfigurator.Configure(memoryAppender);

// ACT
_sut.DoWhatever();

// ASSERT - using xunit - change the expression to fit your purposes
Assert.True(memoryAppender.GetEvents().Any(le => le.Level == Level.Warn), "Expected warning messages in the logs");

您不需要通过使用日志接口添加另一层间接层(如果您不想这样做)。多年来我一直使用抽象的方式,但现在正朝着仅使用 MemoryAppender 的方向发展,因为它正在测试实际发生的情况。只需确保在每次测试后 .Clear() 附加程序即可。

【讨论】:

  • 谢谢!我以为会被困在这上面。很有用!
【解决方案2】:

Log4net 不抛出异常:http://logging.apache.org/log4net/release/faq.html

在单元测试中写入磁盘或数据库中的日志会适得其反;重点是自动化。您不必每次运行测试时都检查日志。

如果您确实需要验证是否进行了调用以记录某些内容,则应模拟ILog 接口并断言调用了适当的方法。

如果您使用的是模拟框架,这很简单。如果不是,您可以创建一个实现或部分实现ILogTestLogger 类,并公开显示给定方法被调用次数的额外属性。您的断言将检查方法是否按预期调用。

这是一个要测试的类的示例:

  public class MyComponent
  {
    private readonly ILog _log;

    public MyComponent(ILog log)
    {
      _log = log;
    }

    public string DoSomething(int arg)
    {
      _log.InfoFormat("Argument was [{0}]", arg);
      return arg.ToString();
    }
  }

和测试(使用 Rhino.Mocks 模拟 ILog):

[TestClass]
  public class MyComponentTests
  {
    [TestMethod]
    public void DoSomethingTest()
    {
      var logger = MockRepository.GenerateStub<ILog>();
      var component = new MyComponent(logger);

      var result = component.DoSomething(8);

      Assert.AreEqual("8", result);
      logger.AssertWasCalled(l => l.InfoFormat(Arg<string>.Is.Anything, Arg<int>.Is.Equal(8)));
    }
  }

【讨论】:

  • 除非应用程序的目的是生成日志,否则编写单元测试来验证是否发生了日志记录只是将实现细节泄漏到测试中。测试行为,而不是实现。
  • @bryanbcook 你同意还是不同意这个答案?
  • 我想我更关心这个问题,因为我不想提倡编写验证日志记录的单元测试。
  • @bryanbcook 在某种程度上,我同意,但很多时候这是有效的。就在今天,我必须实现客户的要求,以记录针对 Web 服务的每个身份验证。那么围绕验证方法的单元测试是否包含调用记录器的断言不是有效的吗?同样,我不认为任何实际的日志记录应该发生在单元测试的上下文中,只是被测试的方法正在对其协作者做它应该做的事情。
  • 我同意这一点,因为这是我试图在原始评论中表达的立场:只编写反映类可见行为的测试——如果日志记录是业务需求,那么你绝对应该为此编写测试。我担心的是,当钟摆摆动到另一端太远并且测试指定了会妨碍正确重构的琐碎实现细节时。
【解决方案3】:

尝试添加:

[assembly: log4net.Config.XmlConfigurator()]

AssemblyInfo.cs(或以任何其他方式初始化log4net)。

或者按照in this answer的建议尝试使用AssemblyInitialize

【讨论】:

    【解决方案4】:

    这是您的 log4net 配置。现在它可能在 web/bin 中的 web.config 或 log4net.config 文件中。您必须将其放置在一个公共位置,并使其可被 Web 应用程序和测试发现。或者你必须把它放到你的 unittest.project=>app.config 文件中。但是如果你有很多测试项目,它会在很多地方重复。所以理想的做法是把它放在一个共同的地方。

    【讨论】:

    • 我之前试过,但它抛出了这个扩展:“单元测试适配器抛出异常:'Microsoft.VisualStudio.TestTools.Diagnostics.EqtTrace'的类型初始化器抛出异常。配置系统初始化失败无法识别的配置节 log4net(././.)。”
    • 我在单元测试中也有对 log4net 的引用,在它的 assemblyInfo 中我添加了程序集:[assembly: log4net.Config.XmlConfigurator(ConfigFile="App.config", Watch = true)]
    • 你定义了 log4net 部分吗?
    • 我错过了它,我添加了它 - 现在它不会抛出异常但也不会写入 log4net ...
    • 您在哪里配置了日志?在 bin 文件夹中?如果是的话,你检查过你的测试项目的 bin 吗?
    【解决方案5】:

    如果其他解决方案都不适合您,这是另一种可能的解决方案...

    尝试将日志文件写入 c 驱动器的根目录。 默认情况下,我将 log4net 设置为写入当前目录,该目录始终是运行单元测试的目录,对吗?... 。 错误的!我正在使用 MS 单元测试运行带有 vs 2012 的 windows 8,并将文件写入本地临时目录,该目录在单元测试完成后被删除。在我的设置中,它将文件写入此处:

    C:\Users\[myself]\AppData\Local\Temp\TestResults
    

    最后,我现在编写的任何单元测试都将使用完整的绝对日志文件路径,而不是相对路径。

    【讨论】:

    • 为什么?这整个线程很奇怪。 Log4net 提供了开箱即用的能力,无需 IO 操作或使用模拟,即可进行简单的基于状态的测试,但每个人都想以艰难的方式去做。奇怪。人们似乎还认为日志记录只记录在磁盘上。 Log4net 是一种抽象,因此您可以登录到任何您想要的内容:天蓝色表存储... 0Mq .. 推特流... ... arrrrggh 这毫无意义!!!!每个人都只是在你的测试中登录到磁盘,让你的生活变得艰难。 :P
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多