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