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
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:
next inject the IFileSystem in the Controller
and of course configure the dependency injection in the startup
now in the Controller ActionResult use the
_fileSystem.File.ReadAllBytes(path)
instead ofSystem.IO.File.ReadAllBytes(path)
Now in te test class just inject the IFileSystem Mock in the constuctor
And setup _fileSystem.File.ReadAllBytes:
expected is
new byte[]
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.