【发布时间】:2009-10-05 12:14:39
【问题描述】:
我有一个使用 log4net 的组件。我想创建单元测试,以验证某些错误条件会导致正确的日志记录。
我认为最好的方法是创建一个 ILogAppender 实现,例如一个模拟。然后,我会在测试设置期间将日志附加程序添加到 log4net,检查测试验证期间写入的内容,并在测试拆卸期间再次将其删除。
这可能吗?
【问题讨论】:
我有一个使用 log4net 的组件。我想创建单元测试,以验证某些错误条件会导致正确的日志记录。
我认为最好的方法是创建一个 ILogAppender 实现,例如一个模拟。然后,我会在测试设置期间将日志附加程序添加到 log4net,检查测试验证期间写入的内容,并在测试拆卸期间再次将其删除。
这可能吗?
【问题讨论】:
使用 BasicConfigurator 可以进行单元测试(OP 要求的,但不是主题行中的要求)。其他答案抓取特定记录器的输出。
我想要它全部(这是网站内的“自测”页面)。最后我基本上做了以下事情:
var root = ((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Root;
var attachable = root as IAppenderAttachable;
var appender = new log4net.Appender.MemoryAppender();
if(attachable!=null)
attachable.AddAppender(appender);
// do stuff
var loggingEvents = appender.GetEvents();
foreach (var loggingEvent in loggingEvents)
loggingEvent.WriteRenderedMessage(writer);
if(attachable!=null)
attachable.RemoveAppender(appender);
...但按照@Pawel 的方法包装为一次性用品
更新:Pawel 的回答已被删除,所以我在此处添加他的链接: Programmatically check Log4Net log.
【讨论】:
我一直在使用the BasicConfigurator 配置了MemoryAppender。此附加程序可让您访问测试期间记录的内存中消息。
【讨论】:
ILog 的存根实现并将其注入我的所有类:-)
以下代码最初是在apache mailing list archives上找到的,应该可以解决代码中添加和删除log4net appenders的问题
/// <summary>
/// dataLog
/// </summary>
protected static readonly IDeviceCommunicationsLog dataLog =
DeviceCommunicationsLogManager.GetLogger("LIS3.Data");
Each connection adds and removes a file appender programmatically:
/// <summary>
/// add connection specific appender
/// </summary>
void AddAppender()
{
// check if logging is endabled
if( this.IsLoggingEnabled() )
{
try
{
// get the interface
IAppenderAttachable connectionAppender = (IAppenderAttachable)this.DataLog.Logger;
// need some application configuration settings
NameValueCollection appSettings = ConfigurationSettings.AppSettings;
// get the layout string
string log4netLayoutString = appSettings["log4net.LIS3.LayoutString"];
if( log4netLayoutString == null )
{
// use default setting
log4netLayoutString = "%d [%x]%n %m%n %P MessageData}%n%n";
}
// get logging path
string log4netPath = appSettings["log4net.Path"];
if( log4netPath == null )
{
// use default path
log4netPath = ".\\";
}
// create the appender
this.rollingFileAppender = new RollingFileAppender();
// setup the appender
this.rollingFileAppender.MaxFileSize = 10000000;
this.rollingFileAppender.MaxSizeRollBackups = 2;
this.rollingFileAppender.RollingStyle = RollingFileAppender.RollingMode.Size;
this.rollingFileAppender.StaticLogFileName = true;
string appenderPath = LogSourceName + ".log";
// log source name may have a colon - if soreplace with underscore
appenderPath = appenderPath.Replace( ':', '_' );
// now add to log4net path
appenderPath = Path.Combine( log4netPath, appenderPath );
// update file property of appender
this.rollingFileAppender.File = appenderPath;
// add the layout
PatternLayout patternLayout = new PatternLayout( log4netLayoutString );
this.rollingFileAppender.Layout = patternLayout;
// add the filter for the log source
NDCFilter sourceFilter = new NDCFilter();
sourceFilter.StringToMatch = this.LogSourceName;
this.rollingFileAppender.AddFilter( sourceFilter);
// now add the deny all filter to end of the chain
DenyAllFilter denyAllFilter = new DenyAllFilter();
this.rollingFileAppender.AddFilter( denyAllFilter );
// activate the options
this.rollingFileAppender.ActivateOptions();
// add the appender
connectionAppender.AddAppender( this.rollingFileAppender );
}
catch( Exception x )
{
this.ErrorLog.Error( "Error creating LIS3 data log appender for " + LogSourceName, x );
}
}
}
/// <summary>
/// remove connection specific appender
/// </summary>
void RemoveAppender()
{
// check if we have one
if( this.rollingFileAppender != null )
{
// cast to required interface
IAppenderAttachable connectionAppender = (IAppenderAttachable)this.DataLog.Logger;
// remove the appendier
connectionAppender.RemoveAppender( rollingFileAppender );
// set to null
this.rollingFileAppender = null;
}
}
【讨论】:
怎么样:
((log4net.Repository.Hierarchy.Logger) theLogger.Logger).RemoveAppender("SomeAppender");
添加相同。
【讨论】: