[英]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.