如何对自定义记录器进行单元测试,它是 tracesource 对象的包装器
How to unit test a custom logger which is a wrapper around tracesource object
我有一个 TraceSource 的包装器 class。我想知道如何对它进行单元测试。由于我需要配置 app.config 文件以便将跟踪侦听器添加到 TraceSource 对象,添加 SwtichSource 等。因此在单元测试 dll 中手动添加 app.config 文件并将其配置为进行单元测试是否有效?我知道我们可以通过编程方式完成所有这些,但是我围绕 TraceSource 创建包装器的方式看起来很棘手,或者可能是不可能的。我们非常欢迎任何建议。
public class Logger : ILogger
{
private const int ERROR_EVENT_ID = 2;
private const int DEBUG_EVENT_ID = 5;
private static TraceSource source;
public Logger(string nameOfComponent)
{
source = new TraceSource(nameOfComponent);
}
public void LogDebug(string message, string methodName)
{
if (string.IsNullOrEmpty(message) || string.IsNullOrEmpty(methodName))
throw new ArgumentNullException("message, methodName can't be null or empty");
source.TraceEvent(TraceEventType.Verbose, DEBUG_EVENT_ID);
}
public void LogError(string methodName, Exception ex)
{
LogError(null, methodName, ex);
}
public void LogError(string message, string methodName, Exception ex) {
if (String.IsNullOrEmpty(message) || String.IsNullOrEmpty(methodName) || ex == null)
throw new ArgumentNullException("message, methodName and exception can't be null or empty");
source.TraceData(TraceEventType.Error, ERROR_EVENT_ID, message, methodName, ex);
}
}
与其让这个 class 为自己创建一个 TraceSource
,不如通过构造函数注入将 TraceSource
注入其中。这样,在您的单元测试中,您可以使用监听器初始化 TraceSource,让您记录对它所做的事情。
您还应确保您的 source
字段不是静态的,因为它由非静态构造函数初始化并由非静态方法使用。
既然你说单元测试,单元测试(而不是验收或集成测试)不应该延伸到外部组件,包括 OS,我假设你想测试逻辑class 但对测试日志消息是否真正到达目的地(文件或数据库或云或其他)不感兴趣。
如果是这样,那么一个解决方案是将 TradeSource
class 包装在一个没有逻辑的非常薄的包装器中(因此不需要单元测试)。这将允许您轻松地注入它或使用工厂创建它、模拟它,从而对 Logger class 中的逻辑进行单元测试。像这样:
public class TraceSourceLogTarget : ITraceSourceLogTarget
{
private TraceSource _traceSource = new TraceSource();
...
public void TraceEvent(TraceEventType eventType, int eventId)
{
_traceSource.TraceEvent(eventType, eventId);
}
...
}
我个人会制作一个更通用的接口(如 ILogTarget
),如果您改变主意并确保您不与这个框架紧密耦合,它可以由其他日志框架实现,但要开始,这会起作用。
我有一个 TraceSource 的包装器 class。我想知道如何对它进行单元测试。由于我需要配置 app.config 文件以便将跟踪侦听器添加到 TraceSource 对象,添加 SwtichSource 等。因此在单元测试 dll 中手动添加 app.config 文件并将其配置为进行单元测试是否有效?我知道我们可以通过编程方式完成所有这些,但是我围绕 TraceSource 创建包装器的方式看起来很棘手,或者可能是不可能的。我们非常欢迎任何建议。
public class Logger : ILogger
{
private const int ERROR_EVENT_ID = 2;
private const int DEBUG_EVENT_ID = 5;
private static TraceSource source;
public Logger(string nameOfComponent)
{
source = new TraceSource(nameOfComponent);
}
public void LogDebug(string message, string methodName)
{
if (string.IsNullOrEmpty(message) || string.IsNullOrEmpty(methodName))
throw new ArgumentNullException("message, methodName can't be null or empty");
source.TraceEvent(TraceEventType.Verbose, DEBUG_EVENT_ID);
}
public void LogError(string methodName, Exception ex)
{
LogError(null, methodName, ex);
}
public void LogError(string message, string methodName, Exception ex) {
if (String.IsNullOrEmpty(message) || String.IsNullOrEmpty(methodName) || ex == null)
throw new ArgumentNullException("message, methodName and exception can't be null or empty");
source.TraceData(TraceEventType.Error, ERROR_EVENT_ID, message, methodName, ex);
}
}
与其让这个 class 为自己创建一个 TraceSource
,不如通过构造函数注入将 TraceSource
注入其中。这样,在您的单元测试中,您可以使用监听器初始化 TraceSource,让您记录对它所做的事情。
您还应确保您的 source
字段不是静态的,因为它由非静态构造函数初始化并由非静态方法使用。
既然你说单元测试,单元测试(而不是验收或集成测试)不应该延伸到外部组件,包括 OS,我假设你想测试逻辑class 但对测试日志消息是否真正到达目的地(文件或数据库或云或其他)不感兴趣。
如果是这样,那么一个解决方案是将 TradeSource
class 包装在一个没有逻辑的非常薄的包装器中(因此不需要单元测试)。这将允许您轻松地注入它或使用工厂创建它、模拟它,从而对 Logger class 中的逻辑进行单元测试。像这样:
public class TraceSourceLogTarget : ITraceSourceLogTarget
{
private TraceSource _traceSource = new TraceSource();
...
public void TraceEvent(TraceEventType eventType, int eventId)
{
_traceSource.TraceEvent(eventType, eventId);
}
...
}
我个人会制作一个更通用的接口(如 ILogTarget
),如果您改变主意并确保您不与这个框架紧密耦合,它可以由其他日志框架实现,但要开始,这会起作用。