我有一个物理文件,我想将它传递给需要IFormFile
类型的控制器方法(用于单元测试)。
我找不到任何实例化IFormFile
接口的类,这意味着我无法创建一个。
如何将物理文件转换为IFormFile
?
答案 0 :(得分:8)
假设您有一个接受[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);
}
IFormFile
使用像Moq这样的模拟框架。您可以使用物理文件来模拟[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));
}
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;
}
可以将模拟的排列提取到扩展方法中以供重用。
var physicalFile = new FileInfo("filePath");
IFormFile formFile = physicalFile.AsMockIFormFile();
并使用
var loader = Page.FindControl("ClientResourceIncludes");
var toRemove = new List<ClientDependencyInclude>();
foreach (ClientDependencyInclude ctl in loader.Controls)
{
if (ctl.FilePath.Contains("/Resources/Search/SearchSkinObjectPreview.css")
|| ctl.FilePath.Contains("/Portals/_default/admin.css"))
toRemove.Add(ctl);
}
}
foreach (var ctl in toRemove)
loader.Controls.Remove(ctl);
答案 1 :(得分:3)
您可以实例化FormFile。这实现了IFormFile
。
答案 2 :(得分:0)
我尝试了Nkosi的答案(使用.NET Core 3.1),但是它只会返回“ System.IO.FileStream”作为文件内容!可能是因为它将FileStream对象从physicalFile.OpenRead()写入输出流,而不是流的实际内容。这个修改后的版本对我有用:
public static IFormFile AsMockIFormFile(this FileInfo physicalFile)
{
var fileMock = new Mock<IFormFile>();
var ms = new MemoryStream();
var writer = new StreamWriter(ms);
using (FileStream fs = physicalFile.OpenRead())
{
byte[] b = new byte[1024];
UTF8Encoding temp = new UTF8Encoding(true);
while (fs.Read(b, 0, b.Length) > 0)
{
writer.WriteLine(temp.GetString(b));
}
}
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 as needed
return fileMock.Object;
}