我正在为我创建的记录器类编写一些单元测试,我想模拟文件类。我找不到我需要用来创建MOQ的接口......那么如何在没有接口的情况下成功MOQ一个类?
我还不清楚如何在没有可用接口的情况下使用依赖注入:
private FileInfo _logFile;
public LogEventProcessorTextFile(FileInfo logFile) {
_logFile = logFile;
}
当我真的想做这样的事情时(注意IFileInfo而不是FileInfo):
private IFileInfo _logFile;
public LogEventProcessorTextFile(IFileInfo logFile) {
_logFile = logFile;
}
答案 0 :(得分:32)
设计代码,以便不使用直接访问FileInfo
类,而是访问具有相同功能的接口(以IFileInfo
命名)。在生产代码中,您将使用一个只将其所有功能委托给系统FileInfo
类的类,但对于单元测试,您可以模拟该接口。
例如,在我根据当前日期采取不同行动的应用程序中,我声明了以下界面:
interface IDateTimeProvider
{
DateTime Today();
}
生产课只是:
class DateTimeProvider : IDateTimeProvider
{
public DateTime Today()
{
return DateTime.Today;
}
}
您可以使用依赖注入引擎来补充此方法,以确定是否应在每种情况下使用真实类或模拟。
答案 1 :(得分:19)
使用SystemWrapper,这是一个为许多.NET类提供接口和可模拟包装类的库,这些类本身不实现接口。
答案 2 :(得分:2)
这可以帮助您轻松创建静态或不可模拟的第三方类的包装类。此工具将在Visual Studio项目上生成Interface和任何现有类(如System.IO)的具体包装类。
答案 3 :(得分:0)
将以下 nuget 包添加到您的 csproj:
<ItemGroup>
<PackageReference Include="System.IO.Abstractions" Version="13.2.29" />
</ItemGroup>
将 System.IO.Abstractions.FileSystem 注入您的类:
public class FileLogger
{
private readonly IFileSystem fileSystem;
public FileLogger(System.IO.Abstractions.IFileSystem fileSystem) // new FileSystem()
{
this.fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
}
public void LogEventProcessorTextFile(string filePath)
{
IFileInfo fileInfo = fileSystem.FileInfo.FromFileName(filePath);
LogEventProcessorTextFile(fileInfo);
}
private System.IO.Abstractions.IFileInfo _logFile;
public void LogEventProcessorTextFile(IFileInfo logFile) {
_logFile = logFile;
}
}
起订量示例:
private Mock<IFileSystem> FileSystemMock { get; set; }
[SetUp]
public void Setup()
{
var file = Mock.Of<IFileInfo>();
var directoryInfo = Mock.Of<IDirectoryInfo>();
Mock.Get(file).Setup(c => c.Exists).Returns(true);
FileSystemMock = new Mock<IFileSystem>();
FileSystemMock.Setup(c => c.FileInfo.FromFileName(It.IsAny<string>())).Returns(file);
FileSystemMock.Setup(c => c.DirectoryInfo.FromDirectoryName("Settings")).Returns(directoryInfo);
}