如何设置文件系统Mock返回DriveInfo?解决只读属性编译问题
如何Mock只读属性的DriveInfo用于文件系统单元测试
问题核心在于原生DriveInfo的DriveType和AvailableFreeSpace是非虚拟的只读属性,Mock框架(如Moq)无法直接修改或拦截这些属性的返回值。解决思路是通过抽象层解耦,绕过原生DriveInfo的限制。
以下是两种可行方案:
方案1:使用现成的文件系统抽象库(推荐)
直接用System.IO.Abstractions库,它已经为所有System.IO类型提供了可Mock的抽象接口,包括IDriveInfo和IFileSystem,无需自己重复造轮子。
步骤1:安装依赖
通过NuGet安装:
System.IO.Abstractions(核心抽象库)Moq(Mock框架)
步骤2:重构业务代码
让FileStatsUtility依赖IFileSystem而非原生类型:
public class FileStatsUtility { private readonly IFileSystem _fileSystem; public FileStatsUtility(IFileSystem fileSystem) { _fileSystem = fileSystem; } public long GetFreeSpaceMb(string drivePath) { var driveInfo = _fileSystem.DriveInfo.FromDriveName(drivePath); if (driveInfo.DriveType != DriveType.Fixed) { throw new InvalidOperationException("仅支持固定磁盘"); } return driveInfo.AvailableFreeSpace / (1024 * 1024); } }
步骤3:编写Mock测试
直接MockIDriveInfo并注入到IFileSystem中:
[TestClass] public class FileStatsUtilityTests { [TestMethod] public void GetFreeSpaceMb_ReturnsCorrectValue_ForFixedDrive() { // Arrange var mockDrive = new Mock<IDriveInfo>(); // 设置只读属性的返回值 mockDrive.Setup(d => d.DriveType).Returns(DriveType.Fixed); mockDrive.Setup(d => d.AvailableFreeSpace).Returns(500 * 1024 * 1024); // 500MB var mockFileSystem = new Mock<IFileSystem>(); mockFileSystem.Setup(f => f.DriveInfo.FromDriveName("C:\\")) .Returns(mockDrive.Object); var utility = new FileStatsUtility(mockFileSystem.Object); // Act var result = utility.GetFreeSpaceMb("C:\\"); // Assert Assert.AreEqual(500, result); } }
方案2:手动封装DriveInfo抽象
如果不想引入第三方库,可以自己定义抽象接口和包装类:
步骤1:定义抽象接口
public interface IDriveInfo { DriveType DriveType { get; } long AvailableFreeSpace { get; } // 根据业务需求添加其他属性/方法 }
步骤2:实现包装类
用原生DriveInfo实现上述接口,供生产环境使用:
public class DriveInfoWrapper : IDriveInfo { private readonly DriveInfo _innerDrive; public DriveInfoWrapper(string drivePath) { _innerDrive = new DriveInfo(drivePath); } public DriveType DriveType => _innerDrive.DriveType; public long AvailableFreeSpace => _innerDrive.AvailableFreeSpace; }
步骤3:修改业务类依赖
让FileStatsUtility依赖IDriveInfo的创建逻辑(比如注入工厂或直接依赖Func<string, IDriveInfo>):
public class FileStatsUtility { private readonly Func<string, IDriveInfo> _driveInfoFactory; public FileStatsUtility(Func<string, IDriveInfo> driveInfoFactory) { _driveInfoFactory = driveInfoFactory; } public long GetFreeSpaceMb(string drivePath) { var driveInfo = _driveInfoFactory(drivePath); if (driveInfo.DriveType != DriveType.Fixed) { throw new InvalidOperationException("仅支持固定磁盘"); } return driveInfo.AvailableFreeSpace / (1024 * 1024); } }
步骤4:编写Mock测试
MockIDriveInfo并传入工厂委托:
[TestMethod] public void GetFreeSpaceMb_ReturnsCorrectValue_ForFixedDrive() { // Arrange var mockDrive = new Mock<IDriveInfo>(); mockDrive.Setup(d => d.DriveType).Returns(DriveType.Fixed); mockDrive.Setup(d => d.AvailableFreeSpace).Returns(500 * 1024 * 1024); var utility = new FileStatsUtility(_ => mockDrive.Object); // Act var result = utility.GetFreeSpaceMb("C:\\"); // Assert Assert.AreEqual(500, result); }
内容的提问来源于stack exchange,提问作者Lucas Hofman
相关产品推荐
相关产品推荐

