单元测试中Directory.GetCurrentDirectory抛出DirectoryNotFoundException问题咨询
问题原因
单元测试的默认运行目录和Web项目的运行目录不一致,测试执行路径下不存在wwwroot/html/myfile.html对应的目录结构,所以调用Directory.GetCurrentDirectory()拼接路径后读取文件会触发目录不存在异常。
可行解决方案
方案1:抽象文件系统依赖,支持Mock(可维护性最优)
不要直接调用静态的Directory、File类,将文件操作抽象为接口注入到Service中,单元测试时可以自由Mock接口返回值,避免依赖真实文件系统。
实现步骤:
- 定义抽象接口
public interface IFileSystem { string GetCurrentDirectory(); string ReadAllText(string path); }
- 实现真实运行时的版本
public class RealFileSystem : IFileSystem { public string GetCurrentDirectory() => Directory.GetCurrentDirectory(); public string ReadAllText(string path) => File.ReadAllText(path); }
- 改造Service类,通过构造函数注入IFileSystem
public class Service { private readonly ISomeRepository _someRepository; private readonly IFileSystem _fileSystem; // 构造函数注入依赖 public Service(ISomeRepository someRepository, IFileSystem fileSystem) { _someRepository = someRepository; _fileSystem = fileSystem; } public async Task<ReponseViewModel> TestedMethod(userData vm) { var anything = await _someRepository.GetSomething(vm.Email); var template = GetTemplate(url); return something; } private string GetTemplate(string url) { var template = _fileSystem.ReadAllText( Path.Combine( _fileSystem.GetCurrentDirectory(), "wwwroot", "html", "myfile.html")); return template; } }
- 单元测试中Mock IFileSystem的返回值
[Fact] public async Task someMethod() { // Arrange var userData = new userData { Email = "test@test.com" }; _someRepository.Setup(x => x.GetSomething(It.IsAny<string>())).ReturnsAsync(Faker()); // Mock文件系统,直接返回测试用的模板内容,不需要真实文件 var mockFileSystem = new Mock<IFileSystem>(); mockFileSystem.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns("测试用的模板内容"); var service= new Service(_someRepository.Object, mockFileSystem.Object); // Act var result = await service.TestedMethod(userData); // Assert Assert.False(result.Success); }
方案2:直接修改当前工作目录(无需改动业务代码)
Directory.GetCurrentDirectory()的返回值和Environment.CurrentDirectory完全一致,直接在测试Arrange阶段修改该属性值为你想要的路径即可,测试结束后记得恢复原值避免影响其他测试:
[Fact] public async Task someMethod() { // 保存原有工作目录 var originalDir = Environment.CurrentDirectory; try { // 设置为你存放测试文件的目录,比如项目根目录路径 Environment.CurrentDirectory = @"C:\你的项目路径"; // 原有测试逻辑 var userData = new userData { Email = "test@test.com" }; _someRepository.Setup(x => x.GetSomething(It.IsAny<string>())).ReturnsAsync(Faker()); var service= new Service(); var result = await service.TestedMethod(userData); Assert.False(result.Success); } finally { // 恢复原有目录,消除全局副作用 Environment.CurrentDirectory = originalDir; } }
方案3:配置静态文件复制到测试输出目录(无需改动代码)
将Web项目中wwwroot/html/myfile.html文件的属性设置为如果较新则复制到输出目录,同时在单元测试项目中也按照相同层级创建wwwroot/html目录存放测试用的html文件,同样设置复制属性,单元测试运行时输出目录就会存在对应的文件结构,不会触发目录不存在异常。
内容的提问来源于stack exchange,提问作者leafar29
相关产品推荐
相关产品推荐

