Home > Enterprise >  C# UnitTests Mock File ReadAllBytes throws System.IO.FileNotFoundException
C# UnitTests Mock File ReadAllBytes throws System.IO.FileNotFoundException

Time:08-06

In the controller i have an action result that returns a FileStreamResult object, before that the action uses the byte[] ReadAllBytes(string path) of the File class.

the action result:

public async Task<IActionResult> Download(string path)
{
    var myfile = System.IO.File.ReadAllBytes(path);

    MemoryStream stream = new MemoryStream(myfile);

    return new FileStreamResult(stream, "application/pdf");
}

in my xUnit test project i'm using Moq for setups.

the mock:

using IFileSystem = System.IO.Abstractions.IFileSystem;

private readonly Mock<IFileSystem> _fileSystem = new Mock<IFileSystem>();

the test method:

[Fact]
public async Task Download_ShouldReturnPdfAsFileStreamResult_WhenIsFoundByPath()
{
    //Arrange
    var expected = new byte[]
    {
        68, 101, 109, 111, 32, 116, 101, 120, 116, 32, 99, 111, 110, 116,
        101, 110, 255, 253, 0, 43, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101,
        0, 32, 0, 116, 0, 101, 0, 120, 0, 116
    };

    var path = _fixture.Create<string>();

    _fileSystem.Setup(f => f.File.ReadAllBytes(It.IsAny<string>()))
        .Returns(expected);

    //Act
    var result = await _sutController.Download(path )
        .ConfigureAwait(false) as FileStreamResult;

    //Assert
    result.Should().NotBeNull();
    //...
}

now when i run test i get this exception:

Message: 

System.IO.FileNotFoundException : Could not find file 'C:\Users\Admin\Desktop\GF\Tests\GF.Web.Controllers.Tests\bin\Debug\net6.0\Path69bdc5aa-695a-4779-b38e-12cb2df4c21a'.

  Stack Trace: 
SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
OSFileStreamStrategy.ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
FileStreamHelpers.ChooseStrategy(FileStream fileStream, String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize)
File.ReadAllBytes(String path)

CodePudding user response:

The propoer way to do this as Alexander suggested in the comments is like this:

first start install the nuget package https://www.nuget.org/packages/System.IO.Abstractions/ in the web and unit test project:

Install-Package System.IO.Abstractions

next inject the IFileSystem in the Controller

public class DownloadsController : Controller
{
    private readonly IFileSystem _fileSystem;

    public DownloadsController(IFileSystem fileSystem)
    {
        _fileSystem = fileSystem;
    }
    ///Code ....
}

and of course configure the dependency injection in the startup

now in the Controller ActionResult use the _fileSystem.File.ReadAllBytes(path) instead of System.IO.File.ReadAllBytes(path)

Now in te test class just inject the IFileSystem Mock in the constuctor

using IFileSystem = System.IO.Abstractions.IFileSystem;
private readonly Mock<IFileSystem> _fileSystem = new Mock<IFileSystem>();

public DownloadsControllerTests()
{
      _sutController = new DownloadsController(_fileSystem.Object);
}

And setup _fileSystem.File.ReadAllBytes:

_fileSystem.Setup(f => f.File.ReadAllBytes(It.IsAny<string>()))
                .Returns(expected).Verifiable();

expected is new byte[]

  • Related