单元测试 - 模拟 ILogger returns null
Unit test - mocking ILogger returns null
我有以下 class:
public class UkFileHandler: FileHandler<UkFileHandler.FileMapper>
{
public class FileMapper : LookUpFieldDefinition
{
public int Name => 1;
public int Address1 => 4;
public int Address2 => 5;
}
public UkFileHandler(ILoggerFactory loggerFactory, IRecordParser recordParser,
IUnzipper unzipper, IFileStore fileStore, IRecordWriter writer)
: base(recordParser, unzipper, fileStore, writer)
{
Logger = loggerFactory.Create<UkFileHandler>();
}
protected override ILogger Logger { get; }
我试图在我的单元测试中模拟这个,我的尝试如下:
[Test]
public void Test()
{
var mockLoggerFactory = new Mock<ILoggerFactory>();
var mockedILogger = new Mock<ILogger>();
mockLoggerFactory.Setup(lf=> lf.Create<UkFileHandler>()).Returns(mockedILogger.Object);
var mockUnzipper = new Mock<IUnzipper>();
var mockFileStore = new Mock<IFileStore>();
var mockFileWriter = new Mock<IRecordWriter>();
var mockFileHandler = new Mock<UkFileHandler>
(mockLoggerFactory.Object, new RecordParser(mockLoggerFactory.Object),
mockUnzipper.Object, mockFileStore.Object, mockFileWriter.Object);
// commented out code which calls method
Assert.IsNotNull(result);
}
我使用的是自定义 ILoggerFactory
,如下所示:
public interface ILoggerFactory
{
ILogger Create<T>();
}
}
我的问题是,当 运行 我的测试时,Logger
实例为 Null。我无法弄清楚我错过了什么地方 - 有人能帮忙吗?
问题是:
protected override ILogger Logger { get; }
在您的层次结构中,Logger 属性 是虚拟的或抽象的。但是有一个简单的修复方法。
只需将此 getter 转换为 UkFileHandler
中的完整 属性。像这样:
public class UkFileHandler: FileHandler<UkFileHandler.FileMapper>
{
private readonly ILogger logger;
public class FileMapper : LookUpFieldDefinition
{
public int Name => 1;
public int Address1 => 4;
public int Address2 => 5;
}
public UkFileHandler(ILoggerFactory loggerFactory, IRecordParser recordParser,
IUnzipper unzipper, IFileStore fileStore, IRecordWriter writer)
: base(recordParser, unzipper, fileStore, writer)
{
logger = loggerFactory.Create<UkFileHandler>();
}
protected override ILogger Logger => logger;
}
第一个问题是,UkFileHandler 是 SUT 吗?如果是,你通常不会嘲笑它。
它为空的原因是 Logger 属性 是虚拟的或抽象的。您在 UkFileHandler 中覆盖它,因此在您的继承层次结构中的某个地方,您将把它标记为虚拟或抽象。一旦你这样做了,Moq 就能够代理它并将它初始化为默认值 (null),即使你在构造函数中设置它也是如此。
有几种方法可以解决它。
鉴于您正在模拟一个实现,mockFileHandler.CallBase = true;
将允许任何未明确设置的内容按照该实现工作。
另一种方法是设置记录器 属性。由于它受到保护,您必须执行以下操作:
mockFileHandler.Protected().Setup<ILogger>("Logger").Returns(mockedILogger.Object);
我有以下 class:
public class UkFileHandler: FileHandler<UkFileHandler.FileMapper>
{
public class FileMapper : LookUpFieldDefinition
{
public int Name => 1;
public int Address1 => 4;
public int Address2 => 5;
}
public UkFileHandler(ILoggerFactory loggerFactory, IRecordParser recordParser,
IUnzipper unzipper, IFileStore fileStore, IRecordWriter writer)
: base(recordParser, unzipper, fileStore, writer)
{
Logger = loggerFactory.Create<UkFileHandler>();
}
protected override ILogger Logger { get; }
我试图在我的单元测试中模拟这个,我的尝试如下:
[Test]
public void Test()
{
var mockLoggerFactory = new Mock<ILoggerFactory>();
var mockedILogger = new Mock<ILogger>();
mockLoggerFactory.Setup(lf=> lf.Create<UkFileHandler>()).Returns(mockedILogger.Object);
var mockUnzipper = new Mock<IUnzipper>();
var mockFileStore = new Mock<IFileStore>();
var mockFileWriter = new Mock<IRecordWriter>();
var mockFileHandler = new Mock<UkFileHandler>
(mockLoggerFactory.Object, new RecordParser(mockLoggerFactory.Object),
mockUnzipper.Object, mockFileStore.Object, mockFileWriter.Object);
// commented out code which calls method
Assert.IsNotNull(result);
}
我使用的是自定义 ILoggerFactory
,如下所示:
public interface ILoggerFactory
{
ILogger Create<T>();
}
}
我的问题是,当 运行 我的测试时,Logger
实例为 Null。我无法弄清楚我错过了什么地方 - 有人能帮忙吗?
问题是:
protected override ILogger Logger { get; }
在您的层次结构中,Logger 属性 是虚拟的或抽象的。但是有一个简单的修复方法。
只需将此 getter 转换为 UkFileHandler
中的完整 属性。像这样:
public class UkFileHandler: FileHandler<UkFileHandler.FileMapper>
{
private readonly ILogger logger;
public class FileMapper : LookUpFieldDefinition
{
public int Name => 1;
public int Address1 => 4;
public int Address2 => 5;
}
public UkFileHandler(ILoggerFactory loggerFactory, IRecordParser recordParser,
IUnzipper unzipper, IFileStore fileStore, IRecordWriter writer)
: base(recordParser, unzipper, fileStore, writer)
{
logger = loggerFactory.Create<UkFileHandler>();
}
protected override ILogger Logger => logger;
}
第一个问题是,UkFileHandler 是 SUT 吗?如果是,你通常不会嘲笑它。
它为空的原因是 Logger 属性 是虚拟的或抽象的。您在 UkFileHandler 中覆盖它,因此在您的继承层次结构中的某个地方,您将把它标记为虚拟或抽象。一旦你这样做了,Moq 就能够代理它并将它初始化为默认值 (null),即使你在构造函数中设置它也是如此。
有几种方法可以解决它。
鉴于您正在模拟一个实现,mockFileHandler.CallBase = true;
将允许任何未明确设置的内容按照该实现工作。
另一种方法是设置记录器 属性。由于它受到保护,您必须执行以下操作:
mockFileHandler.Protected().Setup<ILogger>("Logger").Returns(mockedILogger.Object);