I have a physical file and I want to pass it to my controller method that requires an IFormFile
type (for unit testing).
I can't find any classes that instantiate the IFormFile
interface which means I can't create one.
How can I convert my physical file into an IFormFile
?
Inside the action method, the IFormFile contents are accessible as a Stream. So for IFormFile , you need to save it locally before using the local path. After this, you can get the local file path, namely filePath . In the case of a large file, isn't it taking a lot of time to get the file path after saving it locally?
What is IFormFile. ASP.NET Core has introduced an IFormFile interface that represents transmitted files in an HTTP request. The interface gives us access to metadata like ContentDisposition, ContentType, Length, FileName, and more. IFormFile also provides some methods used to store files.
You can instantiate a FormFile. That implements IFormFile
.
Example in .Net Core 3.1 (assume 'file' is physical path & file):
using var stream = new MemoryStream(File.ReadAllBytes(file).ToArray());
var formFile = new FormFile(stream, 0, stream.Length, "streamFile", file.Split(@"\").Last());
Let's assume you have a controller method that accepts IFormInfo
[HttpPost]
public Task<IActionResult> Upload(IFormFile file) {
FileDetails fileDetails = null;
using (var reader = new StreamReader(file.OpenReadStream())) {
var fileContent = reader.ReadToEnd();
ContentDispositionHeaderValue parsedContentDisposition = null;
if (ContentDispositionHeaderValue.TryParse(file.ContentDisposition, out parsedContentDisposition)) {
fileDetails = new FileDetails {
Filename = parsedContentDisposition.FileName,
Content = fileContent
};
}
}
return Task.FromResult((IActionResult)fileDetails);
}
Using a mocking framework like Moq. You can use a physical file to mock the IFormFile
[TestMethod]
public async Task Controller_Should_Upload_FormFile() {
// Arrange.
var fileMock = new Mock<IFormFile>();
var physicalFile = new FileInfo("filePath");
var ms = new MemoryStream();
var writer = new StreamWriter(ms);
writer.Write(physicalFile.OpenRead());
writer.Flush();
ms.Position = 0;
var fileName = physicalFile.Name;
//Setup mock file using info from physical file
fileMock.Setup(_ => _.FileName).Returns(fileName);
fileMock.Setup(_ => _.Length).Returns(ms.Length);
fileMock.Setup(_ => _.OpenReadStream()).Returns(ms);
fileMock.Setup(_ => _.ContentDisposition).Returns(string.Format("inline; filename={0}", fileName));
//...setup other members as needed.
var sut = new MyController();
var file = fileMock.Object;
// Act.
var result = await sut.Upload(file);
//Assert.
Assert.IsInstanceOfType(result, typeof(IActionResult));
}
The arranging of the mock can be even extracted into an extension method for reuse.
public static IFormFile AsMockIFormFile(this FileInfo physicalFile) {
var fileMock = new Mock<IFormFile>();
var ms = new MemoryStream();
var writer = new StreamWriter(ms);
writer.Write(physicalFile.OpenRead());
writer.Flush();
ms.Position = 0;
var fileName = physicalFile.Name;
//Setup mock file using info from physical file
fileMock.Setup(_ => _.FileName).Returns(fileName);
fileMock.Setup(_ => _.Length).Returns(ms.Length);
fileMock.Setup(m => m.OpenReadStream()).Returns(ms);
fileMock.Setup(m => m.ContentDisposition).Returns(string.Format("inline; filename={0}", fileName));
//...setup other members (code removed for brevity)
return fileMock.Object;
}
and used like
var physicalFile = new FileInfo("filePath");
IFormFile formFile = physicalFile.AsMockIFormFile();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With