skip to Main Content

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:UsersAdminDesktopGFTestsGF.Web.Controllers.TestsbinDebugnet6.0Path69bdc5aa-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)

2

Answers


  1. Chosen as BEST ANSWER

    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[]


  2. There is an alternate pure way to mock(Moq) with out adding any Nuget packages.
    Implement an Interface and class.Then dependency inject the Interface.
    Now you can mock in test class.

     public interface IMyHelper
      {
         byte[] ReadByteArrayFromFile(string path);
      }
    
      public class MyHelper:IMyHelper
     {
        public byte[] ReadByteArrayFromFile(string path)
        {
            byte[] bytes = System.IO.File.ReadAllBytes(path);
            return bytes; 
        }
     }
    
    [TestClass]
          Mock<IMyHelper> myHelper = new Mock<IMyHelper>();
    [TestInitialize]
       public void SetUp()
        {
             myHelper.Setup(x => x.ReadByteArrayFromFile(It.IsAny<string> 
            ())).Returns(new byte[123]);
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search