.NET Core 应用程序中单元测试的模拟日志文件

Mock log file for unit test in .NET Core application

在我的 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 变量的代码进行单元测试。我想以某种方式模拟这个,因为我想为我的测试使用特定的日志数据,但我不确定如何去做。我该怎么做?

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

您或许应该将此行为重构为单独的 class 并将其隐藏在界面后面。我不完全确定 NLog 代码的作用,但你的方法似乎真正做的不是提供日志文件,而是日志文件的名称(你 return fileName)所以这是它可能看起来像:

public interface ILogFileNameProvider 
{
    string GetLogFileName();
}

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

这只是您如何处理它的示例。 naming/structure 以及如何使用它取决于您。 然后可以在当前具有私有方法的 using class 中注入该接口。这个dependency/call可以嘲笑

构造函数注入的用法:

public class LogFileNameUsingService
{
    private readonly ILogFileNameProvider _logFileNameProvider;

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

xUnit and AutoMocker为例进行测试:

[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
}

这还允许您换出当前逻辑以便稍后获取日志文件,而无需更改现有逻辑 class。