C# 单元测试-模拟ILogger返回null
我有以下课程:C# 单元测试-模拟ILogger返回null,c#,asp.net-core,logging,nunit,moq,C#,Asp.net Core,Logging,Nunit,Moq,我有以下课程: public class UkFileHandler: FileHandler<UkFileHandler.FileMapper> { public class FileMapper : LookUpFieldDefinition { public int Name => 1; public int Address1 => 4; publ
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; }
我的问题是,在运行测试时,Logger
实例为空。我不知道我在哪里遗漏了什么-有人能帮忙吗?问题在于:
protected override ILogger Logger { get; }
在层次结构中,记录器属性是虚拟的或抽象的。但有一个简单的解决办法。
只需将此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:FileHandler
{
专用只读ILogger记录器;
公共类文件映射器:LookUpFieldDefinition
{
public int Name=>1;
公共int地址1=>4;
公共int地址2=>5;
}
公共UkFileHandler(ILoggerFactory loggerFactory、IRecordParser recordParser、,
IUnzipper unzipper,IFileStore文件存储,IRecordWriter)
:base(recordParser、解压缩、文件存储、写入程序)
{
logger=loggerFactory.Create();
}
受保护的覆盖ILogger=>Logger;
}
第一个问题是,UkFileHandler是SUT吗?如果是,你通常不会嘲笑它
它为null的原因是记录器属性是虚拟的或抽象的。您将在UkFileHandler中重写它,因此在继承层次结构的某个地方,您将它标记为虚拟或抽象。一旦您这样做了,Moq就能够代理它并将其初始化为默认值(null),即使您正在构造函数中设置它
有几种方法可以解决这个问题
假设您正在模拟一个实现,mockFileHandler.CallBase=true代码>将允许任何未明确设置的内容按照实现工作
另一种方法是设置Logger属性。由于它受到保护,您必须执行以下操作:
mockFileHandler.Protected().Setup<ILogger>("Logger").Returns(mockedILogger.Object);
mockFileHandler.Protected().Setup(“Logger”).Returns(mockedILogger.Object);
为什么您有一个定制的记录器工厂?您可以像这样插入默认记录器:ILogger
您是否验证了UkFileHandler构造函数是否实际被调用?是的,它是@KlausGütter虽然我现在同意原因,但鉴于您已将其更改为与我先前发布的答案一致,此补救措施将被视为不好的做法。避免更新SUT以适应测试,特别是当Moq有支持来处理它时。下次你要有信心,坚持你的答案,或者在适当的时候给予表扬。我没有改变我的答案。刚刚编辑了文本。这也是你今天第二次在这里的答案中要求投票。我不确定stackoverflow的适度性是否允许。我想你把我和其他人搞混了,因为这是我过去几天唯一的帖子。我不是在要求投票,这也不会困扰我。
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;
}
mockFileHandler.Protected().Setup<ILogger>("Logger").Returns(mockedILogger.Object);