【问题标题】:Throw UnauthorizedAccessException from System.IO.Abstractions从 System.IO.Abstractions 抛出 UnauthorizedAccessException
【发布时间】:2019-03-25 09:26:59
【问题描述】:

我使用System.IO.Abstractions (https://github.com/System-IO-Abstractions) 允许我将IFileSystem 注入我的班级。我最近添加了一段代码来捕获当用户尝试在他们没有写入权限的目录中创建文件时抛出的UnauthorizedAccessException

有没有办法在System.IO.Abstractions中设置目录的访问权限?

下面的代码和我来的一样接近(MockFileSystem 来自System.IO.Abstractions)。 AccessControlSections 描述是

指定要保存或加载安全描述符的哪些部分

所以看来我需要设置某种安全描述符,但我找不到任何相关信息 - 或者这是否是正确的方法。

var mockFileSystem = new MockFileSystem();
mockFileSystem.Directory.CreateDirectory("C:\\Test", new DirectorySecurity("C:\\Test", AccessControlSections.None));

// This should throw an UnauthorizedAccessException
mockFileSystem.File.Create("C:\\Test\\File.txt");

【问题讨论】:

  • 看起来 Directory.SetAccessControl 是 BCL 中 Directory.SetAccessControl 的包装,所以只需遵循那些 MSDN 文档?
  • 这个库看起来付出了很多努力却收效甚微
  • @MichaelRandall 这是一个巨大的收获,我可以测试我的整个应用程序,而无需依赖构建/测试机器上实际存在的任何文件。我还可以围绕文件系统状态编写测试,因为我可以将它注入到我的类中。
  • @TheGeneral,让你的代码可测试一点收获吗?

标签: c# testing filesystems


【解决方案1】:

我尝试过这样的事情但失败了:

const string path = @"C:\temp\incoming";
var fileSystem = new MockFileSystem();
fileSystem.AddDirectory(path);
var diFactory = fileSystem.DirectoryInfo;
var directoryInfo = diFactory.FromDirectoryName(path);
var directorySecurity = directoryInfo.GetAccessControl();
var currentUser = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
directorySecurity.AddAccessRule(new FileSystemAccessRule(currentUser , FileSystemRights.Read, AccessControlType.Allow));

我仍然认为这或多或少是要走的路,不幸的是它不起作用:-(

也许我为 AccessRule 指定的用户不正确,我也尝试过其他人但无济于事:

var adminUser = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
// -> Doesn't work either..

无论如何,最后我创建了这个肮脏的解决方法来测试它,而且很明显:

var mockFileSystem = new Mock<IFileSystem>();
mockFileSystem.Setup(x => x.File.Create(It.IsAny<string>())).Throws(new Exception());

【讨论】:

  • 请检查我的回答。如果您有兴趣,它可能会有所帮助。
【解决方案2】:

您可以为IFileSystem 创建一个模拟来设置您想要抛出异常的方法,然后创建一个MockFileSystem 以仅在必要时使用。您可以设置模拟以在仅调用某些方法时返回“真实”文件系统。在下面的例子中,我只想在使用Path 时使用MockFileSystem

您必须像这样设置您的测试(请阅读 cmets):

[Fact]
public async void FailWhenCopyFails()
{
   // Arrange
   var file = Substitute.For<IFile>(); // fake File to throw UnauthorizedAccessException
   file
      .When(x => x.WriteAllBytesAsync(Arg.Any<string>(), Arg.Any<byte[]>()))
      .Do(x => { throw new UnauthorizedAccessException(); });

   file.Exists("C:\\Downloads\\" + "eclipse.exe").Returns(true);

   var fileSystem = Substitute.For<IFileSystem>(); // fake file system
   var mockFileSystem = new MockFileSystem(); // "real" file system to be used only when necessary
   fileSystem.File.Returns(file); // pass the File mock which will throw the exception
   fileSystem.Path.Returns(mockFileSystem.Path); // the "real" Path is necessary to make the test pass

   var httpResponseMessage = new HttpResponseMessage() { StatusCode = HttpStatusCode.OK };
   var httpClient = new HttpClient(new MockHttpMessageHandler(httpResponseMessage));
   var downloader = new DownloadManager(httpClient, fileSystem);

   // Act
   await Assert.ThrowsAsync<UnauthorizedAccessException>(() => downloader.DownloadFile(new Uri(eclipseUrl), downloadFolder));

   // Assert
   downloader.IsSuccess().Should().BeFalse();
}

在我的情况下,如果 http 客户端无法在下载文件夹中创建下载的文件,我想验证下载是否失败(如果它不能覆盖已经存在的 C:\Downloads\eclipse.exe,它应该会失败) .

【讨论】:

    猜你喜欢
    • 2016-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-09
    • 1970-01-01
    相关资源
    最近更新 更多