【发布时间】:2016-08-19 21:42:52
【问题描述】:
我想编写用于在 ASP.NET Core 中上传文件的测试,但似乎找不到模拟/实例化从 IFormFile 派生的对象的好方法。
关于如何做到这一点的任何建议?
【问题讨论】:
标签: c# unit-testing asp.net-core asp.net-core-mvc
我想编写用于在 ASP.NET Core 中上传文件的测试,但似乎找不到模拟/实例化从 IFormFile 派生的对象的好方法。
关于如何做到这一点的任何建议?
【问题讨论】:
标签: c# unit-testing asp.net-core asp.net-core-mvc
假设你有一个像..这样的控制器
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));
}
}
【讨论】:
创建一个实际的内存实例会更容易
var bytes = Encoding.UTF8.GetBytes("This is a dummy file");
IFormFile file = new FormFile(new MemoryStream(bytes), 0, bytes.Length, "Data", "dummy.txt");
【讨论】:
content 的字符串变量中。所以FormFile 的第三个参数是content.Length。
添加 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
);
}
【讨论】:
我无法模拟 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;
}
【讨论】: