.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。
在我的 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。