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);