簡體   English   中英

如何在 ASP.NET Core 中為單元/集成測試模擬 IFormFile?

[英]How to mock an IFormFile for a unit/integration test in ASP.NET Core?

我想編寫用於在 ASP.NET Core 中上傳文件的測試,但似乎找不到一種很好的方法來模擬/實例化從 IFormFile 派生的IFormFile

關於如何執行此操作的任何建議?

假設你有一個像..

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

...使用IFormFile.OpenReadStream()方法訪問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 類的實例,它現在是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));
    }
}

更容易的是創建一個實際的內存實例

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

添加帶有固定長度的 harishr 答案(這是我的 Blob.Upload() 工作所需的)。

private IFormFile CreateTestFormFile(string p_Name, string p_Content)
{
    byte[] s_Bytes = Encoding.UTF8.GetBytes(p_Content);

    return new FormFile(
        baseStream: new MemoryStream(s_Bytes),
        baseStreamOffset: 0,
        length: s_Bytes.Length,
        name: "Data",
        fileName: p_Name
    );
}

我無法模擬 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;")
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;
}

我正在使用這個 nippet 進行集成測試

public static MultipartFormDataContent CreateTestFile(string fileName, string fileContent)
        {
            var content = new MultipartFormDataContent();
            content.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(fileContent)), "files", fileName);
            return content;
        }

這就是我在集成測試中使用它的方式

[Fact]
        public async Task UploadDocument_ReturnsOk()
        {
            // Arrange
            var provider = TestClaimsProvider.WithUserClaims();
            var client = _factory.CreateClientWithTestAuth(provider);

            // Act
            HttpResponseMessage? resultResponseMessage = await client.PutAsync($"/api/Documents",
                WebApiExtensions.CreateTestFile("test.csv", "content"));

            // Assert
            resultResponseMessage.ShouldHave200Code();
        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM