首页 > 解决方案 > .NET Core 应用程序中单元测试的模拟日志文件

问题描述

在我的 C# 应用程序中,我有一个getLogFile通过调用GetLogFile()方法设置的:

private static string getLogFile = GetLogFile();

private static string GetLogFile()
{
    var fileTarget = (FileTarget)LogManager.Configuration.FindTargetByName("file-target");
    var logEventInfo = new LogEventInfo();
    string fileName = fileTarget.FileName.Render(logEventInfo);
    if (!File.Exists(fileName))
        throw new Exception("Log file does not exist.");
    return fileName;
}

我现在正在尝试对一些需要设置getLogFile变量的代码进行单元测试。我想以某种方式模拟它,因为我想使用特定的日志数据进行测试,但不知道如何去做。我怎样才能做到这一点?

标签: c#asp.netunit-testing.net-corenlog

解决方案


“模拟”一个private static领域或方法是不可能的。将这种方法作为另一个类的私有成员,这听起来像是违反了单一责任原则。

您可能应该将此行为重构为一个单独的类并将其隐藏在接口后面。我不完全确定 NLog 代码的作用,但您的方法似乎真正做的不是提供日志文件,而是提供日志文件的名称(您返回fileName)所以这就是它的样子:

public interface ILogFileNameProvider 
{
    string GetLogFileName();
}

public class DefaultLogFileNameProvider : ILogFileNameProvider
{
    public string GetLogFileName()
    {
         // your code ommitted
    }
}

这只是一个关于如何处理它的例子。命名/结构以及如何使用它取决于您。然后可以将该接口注入到当前具有私有方法的 using 类中。可以模拟此依赖项/调用。

构造函数注入的用法:

public class LogFileNameUsingService
{
    private readonly ILogFileNameProvider _logFileNameProvider;

    public LogFileNameUsingService(ILogFileNameProvider logFileNameProvider)
    {
        _logFileNameProvider = logFileNameProvider;
    }
}

xUnitAutoMocker为例进行测试:

[Theory]
public void TestWithMockedLogFileName()
{
    //Arrange
    var mocker = new AutoMocker();
    var logFileNameProviderMock = mocker.GetMock<ILogFileNameProvider>();
    logFileNameProviderMock.Setup(x => x.GetLogFileName()).Returns("your mocked file name.log");
    var sut = mocker.CreateInstance<LogFileNameUsingService>();
    //Act
    var result = sut.TestedMethodWhichUsesLogFileName();
    //Assert whatever you want to test
}

这也允许您交换当前逻辑以稍后获取日志文件,而无需更改现有类的逻辑。


推荐阅读