从物理文件中实例化IFormFile

时间:2016-06-04 09:43:28

标签: c# asp.net unit-testing asp.net-core

我有一个物理文件,我想将它传递给需要IFormFile类型的控制器方法(用于单元测试)。

我找不到任何实例化IFormFile接口的类,这意味着我无法创建一个。

如何将物理文件转换为IFormFile

3 个答案:

答案 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;
    }