【问题标题】:How to mock an IFormFile for a unit/integration test in ASP.NET Core?如何在 ASP.NET Core 中模拟 IFormFile 以进行单元/集成测试?
【发布时间】:2016-08-19 21:42:52
【问题描述】:

我想编写用于在 ASP.NET Core 中上传文件的测试,但似乎找不到模拟/实例化从 IFormFile 派生的对象的好方法。

关于如何做到这一点的任何建议?

【问题讨论】:

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


    【解决方案1】:

    假设你有一个像..这样的控制器

    public class MyController : Controller {
        public Task<IActionResult> UploadSingle(IFormFile file) {...}
    }
    

    ...IFormFile.OpenReadStream() 是通过被测方法访问的。

    您可以使用Moq 模拟框架创建一个测试来模拟流数据。

    [TestClass]
    public class IFormFileUnitTests {
        [TestMethod]
        public async Task Should_Upload_Single_File() {
            //Arrange
            var fileMock = new Mock<IFormFile>();
            //Setup mock file using a memory stream
            var content = "Hello World from a Fake File";
            var fileName = "test.pdf";
            var ms = new MemoryStream();
            var writer = new StreamWriter(ms);
            writer.Write(content);
            writer.Flush();
            ms.Position = 0;
            fileMock.Setup(_ => _.OpenReadStream()).Returns(ms);
            fileMock.Setup(_ => _.FileName).Returns(fileName);
            fileMock.Setup(_ => _.Length).Returns(ms.Length);
    
            var sut = new MyController();
            var file = fileMock.Object;
    
            //Act
            var result = await sut.UploadSingle(file);
    
            //Assert
            Assert.IsInstanceOfType(result, typeof(IActionResult));
        }
    }
    

    或者,从 ASP.NET Core 3.0 开始,使用 FormFile Class 的实例,它现在是 IFormFile 的默认实现。

    这是使用FormFile 类进行上述相同测试的示例

    [TestClass]
    public class IFormFileUnitTests {
        [TestMethod]
        public async Task Should_Upload_Single_File() {
            //Arrange
           
            //Setup mock file using a memory stream
            var content = "Hello World from a Fake File";
            var fileName = "test.pdf";
            var stream = new MemoryStream();
            var writer = new StreamWriter(stream);
            writer.Write(content);
            writer.Flush();
            stream.Position = 0;
    
            //create FormFile with desired data
            IFormFile file = new FormFile(stream, 0, stream.Length, "id_from_form", fileName);
            
            MyController sut = new MyController();
            
            //Act
            var result = await sut.UploadSingle(file);
    
            //Assert
            Assert.IsInstanceOfType(result, typeof(IActionResult));
        }
    }
    

    【讨论】:

      【解决方案2】:

      创建一个实际的内存实例会更容易

       var bytes = Encoding.UTF8.GetBytes("This is a dummy file");
       IFormFile file = new FormFile(new MemoryStream(bytes), 0, bytes.Length, "Data", "dummy.txt");
      

      【讨论】:

      • 您是否参考过它之前存在的位置,如文档中所示 docs.microsoft.com/en-us/dotnet/api/…
      • 这对我不起作用,我的意思是无法读取文件的内容。相反,我必须设置流的长度。我已将文件的内容存储到名为content 的字符串变量中。所以FormFile 的第三个参数是content.Length
      【解决方案3】:

      添加 harishr 的答案并设置长度(这是我的 Blob.Upload() 工作所需要的)。

      private IFormFile CreateTestFormFile(string fileName, string content)
      {
          byte[] bytes = Encoding.UTF8.GetBytes(content);
      
          return new FormFile(
              baseStream: new MemoryStream(bytes),
              baseStreamOffset: 0,
              length: bytes.Length,
              name: "Data",
              fileName: fileName
          );
      }
      

      【讨论】:

        【解决方案4】:

        我无法模拟 IFormFile,因为我遇到了 Stream 问题,所以我最终创建了 FormFile 的实例。如果您对文件使用验证器等,请注意您需要设置内容类型。

                private IFormFile GetFileMock(string contentType, string content)
                {
                    byte[] bytes = Encoding.UTF8.GetBytes(content);
        
                    var file = new FormFile(
                        baseStream: new MemoryStream(bytes),
                        baseStreamOffset: 0,
                        length: bytes.Length,
                        name: "Data",
                        fileName: "dummy.csv"
                    )
                    {
                        Headers = new HeaderDictionary(),
                        ContentType = contentType
                    };
        
                    return file;
                }
                
        

        打电话

         GetFileMock("text/csv", "test;test;")
        

        【讨论】:

        • 我遇到了流问题,您的回答对我有用。
        【解决方案5】:
        private static IFormFileCollection GetFormFileCollection()
        {
            var filesFolder = $"{AppDomain.CurrentDomain.SetupInformation.ApplicationBase}UploadFiles\\";
            List<string> filesPathsListToUpload = new List<string>();
            filesPathsListToUpload.Add($"{filesFolder}UploadFile1.png");
            filesPathsListToUpload.Add($"{filesFolder}UploadFile2.jpg");
            filesPathsListToUpload.Add($"{filesFolder}UploadFile3.bmp");
        
            FormFileCollection filesCollection = new FormFileCollection();
            foreach (var filePath in filesPathsListToUpload)
            {
                var stream = File.OpenRead(filePath);
                IFormFile file = new FormFile(stream, 0, stream.Length, "files", Path.GetFileName(filePath))
                {
                    Headers = new HeaderDictionary(),
                    ContentType = filePath.Split('.')[1] == "jpg" ? "image/jpeg"
                        : filePath.Split('.')[1] == "png" ? "image/png"
                        : "image/bmp",
                };
                
                filesCollection.Add(file);
            }
        
            var httpContext = new DefaultHttpContext();
            httpContext.Request.Headers.Add("Content-Type", "multipart/form-data");
            httpContext.Request.Form = new FormCollection(new Dictionary<string, StringValues>(), filesCollection);
        
            return httpContext.Request.Form.Files;
        }
        

        【讨论】:

        • 请在你的答案中添加一些解释,不要只写一段代码;)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-18
        • 2013-03-25
        • 1970-01-01
        • 2017-09-11
        • 1970-01-01
        • 2019-12-13
        相关资源
        最近更新 更多