使用 XUnit 和 AspNetCore.TestHost 测试 .net 核心网络 api 控制器文件上传
Testing a .net core web api controller file upload using XUnit and AspNetCore.TestHost
我有这个控制器可以上传文件:
[HttpPost]
public async Task<IActionResult> Post([FromForm] FileInformation fileInfo)
{
int newFileVersion = 1;
if (fileInfo == null || fileInfo.Files == null || fileInfo.Files.Count == 0)
return BadRequest("File(s) not found");
try
{
foreach (var locFile in fileInfo.Files)
{
//check for file extension, if not there, return an error
var fileExtension = Path.GetExtension(locFile.FileName);
if (string.IsNullOrEmpty(fileExtension))
return BadRequest("Files must include file extension");
var valid = await fileUtilities.IsFileValid(locFile);
var newFileName = string.Concat(Guid.NewGuid().ToString(),valid.fileExtension);
var newFileLocation = Path.Combine(config.GetSection("StoredFilePath").Value, newFileName);
if (!valid.FileExtensionFound)
{
return BadRequest($"Error {valid.FileExtensionFoundError}");
}
if (!valid.FileSizeAllowed)
{
return BadRequest($"Error: {valid.FileSizeAllowedError}");
}
//check for an existing file in the database. If there is one, increment the file version before the save
var currentFile = await fileUtilities.FileExists(fileInfo, locFile);
if (currentFile != null)
{
newFileVersion = currentFile.Version + 1;
}
//save to the file system
using (var stream = new FileStream(newFileLocation, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
await locFile.CopyToAsync(stream);
}
//save to the db. Check to see if the file exists first. If it does, do an insert, if not, return an error
if (System.IO.File.Exists(newFileLocation))
{
FileUploads upload = new FileUploads
{
EntityId = fileInfo.EntityId,
FileName = locFile.FileName,
ItemId = fileInfo.ItemId.ToString(),
NewFileName = newFileName,
ValidFile = true,
Version = newFileVersion
};
context.FileUploads.Add(upload);
context.SaveChanges();
//TODO: fire event the file has been saved provide Id key to find the record
//upload.Id;
}
else
{
return BadRequest("Error: File Could not be saved");
}
}
}
catch (Exception ex)
{
return BadRequest("Failure to upload files.");
}
return Ok("File Uploaded");
}
我正在尝试使用 XUnit 和 Microsoft.AspNetCore.TestHost 编写单元文本,但我不知道如何编写文件上传测试。这是我用来获取错误请求的一项测试:
[Theory]
[InlineData("POST", "")]
public async Task LibrarianUploadFile_Error(string method, string? data = null)
{
//arrange
var request = new HttpRequestMessage(new HttpMethod(method), $"/api/librarian");
//act
var response = await _client.SendAsync(request);
//assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
本次测试通过。我已经毫无问题地为 GET 方法编写了所有其他测试,我只是不知道如何进行此测试。我想我可以在我的本地测试机器上上传一个测试文件,我只是不知道如何构建 POST.
这是 Class 的我的构造函数:
private readonly HttpClient _client;
public LibrarianUploadFiles()
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var server = new TestServer(new WebHostBuilder()
.UseConfiguration(configuration)
.UseStartup<Startup>());
_client = server.CreateClient();
}
这会创建我需要 GET 的客户端,POST,等等
你需要 post 类似这样吗:
// Act
HttpResponseMessage response;
using (var file = File.OpenRead(@"path\fileName.txt"))
using (var content = new StreamContent(file))
using (var formData = new MultipartFormDataContent())
{
formData.Add(content, "fileInfo", "fileName.txt");
response = await client.PostAsync(url, formData);
}
// Assert
response.EnsureSuccessStatusCode();
这里是问题的最终解决方案。使用@gpaoli 的回答并环顾四周,我得到了这段代码 post 并通过了测试。
//arrange
var request = new HttpRequestMessage(new HttpMethod(method), [url to post]);
using var form = new MultipartFormDataContent();
using var fileContent = new ByteArrayContent(await File.ReadAllBytesAsync(@"c:\files\test.txt"));
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
form.Add(fileContent, "Files", "test.txt");
form.Add(new StringContent("Partner1"), "EntityId");
form.Add(new StringContent(Guid.NewGuid().ToString()), "ItemId");
//act
HttpResponseMessage response;
response = await _client.PostAsync($"/api/librarian", form);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
我遇到的几个问题是添加 stringContent 并确保正确命名文件和字符串内容,以便控制器可以映射值。
我有这个控制器可以上传文件:
[HttpPost]
public async Task<IActionResult> Post([FromForm] FileInformation fileInfo)
{
int newFileVersion = 1;
if (fileInfo == null || fileInfo.Files == null || fileInfo.Files.Count == 0)
return BadRequest("File(s) not found");
try
{
foreach (var locFile in fileInfo.Files)
{
//check for file extension, if not there, return an error
var fileExtension = Path.GetExtension(locFile.FileName);
if (string.IsNullOrEmpty(fileExtension))
return BadRequest("Files must include file extension");
var valid = await fileUtilities.IsFileValid(locFile);
var newFileName = string.Concat(Guid.NewGuid().ToString(),valid.fileExtension);
var newFileLocation = Path.Combine(config.GetSection("StoredFilePath").Value, newFileName);
if (!valid.FileExtensionFound)
{
return BadRequest($"Error {valid.FileExtensionFoundError}");
}
if (!valid.FileSizeAllowed)
{
return BadRequest($"Error: {valid.FileSizeAllowedError}");
}
//check for an existing file in the database. If there is one, increment the file version before the save
var currentFile = await fileUtilities.FileExists(fileInfo, locFile);
if (currentFile != null)
{
newFileVersion = currentFile.Version + 1;
}
//save to the file system
using (var stream = new FileStream(newFileLocation, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
await locFile.CopyToAsync(stream);
}
//save to the db. Check to see if the file exists first. If it does, do an insert, if not, return an error
if (System.IO.File.Exists(newFileLocation))
{
FileUploads upload = new FileUploads
{
EntityId = fileInfo.EntityId,
FileName = locFile.FileName,
ItemId = fileInfo.ItemId.ToString(),
NewFileName = newFileName,
ValidFile = true,
Version = newFileVersion
};
context.FileUploads.Add(upload);
context.SaveChanges();
//TODO: fire event the file has been saved provide Id key to find the record
//upload.Id;
}
else
{
return BadRequest("Error: File Could not be saved");
}
}
}
catch (Exception ex)
{
return BadRequest("Failure to upload files.");
}
return Ok("File Uploaded");
}
我正在尝试使用 XUnit 和 Microsoft.AspNetCore.TestHost 编写单元文本,但我不知道如何编写文件上传测试。这是我用来获取错误请求的一项测试:
[Theory]
[InlineData("POST", "")]
public async Task LibrarianUploadFile_Error(string method, string? data = null)
{
//arrange
var request = new HttpRequestMessage(new HttpMethod(method), $"/api/librarian");
//act
var response = await _client.SendAsync(request);
//assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
本次测试通过。我已经毫无问题地为 GET 方法编写了所有其他测试,我只是不知道如何进行此测试。我想我可以在我的本地测试机器上上传一个测试文件,我只是不知道如何构建 POST.
这是 Class 的我的构造函数:
private readonly HttpClient _client;
public LibrarianUploadFiles()
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var server = new TestServer(new WebHostBuilder()
.UseConfiguration(configuration)
.UseStartup<Startup>());
_client = server.CreateClient();
}
这会创建我需要 GET 的客户端,POST,等等
你需要 post 类似这样吗:
// Act
HttpResponseMessage response;
using (var file = File.OpenRead(@"path\fileName.txt"))
using (var content = new StreamContent(file))
using (var formData = new MultipartFormDataContent())
{
formData.Add(content, "fileInfo", "fileName.txt");
response = await client.PostAsync(url, formData);
}
// Assert
response.EnsureSuccessStatusCode();
这里是问题的最终解决方案。使用@gpaoli 的回答并环顾四周,我得到了这段代码 post 并通过了测试。
//arrange
var request = new HttpRequestMessage(new HttpMethod(method), [url to post]);
using var form = new MultipartFormDataContent();
using var fileContent = new ByteArrayContent(await File.ReadAllBytesAsync(@"c:\files\test.txt"));
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
form.Add(fileContent, "Files", "test.txt");
form.Add(new StringContent("Partner1"), "EntityId");
form.Add(new StringContent(Guid.NewGuid().ToString()), "ItemId");
//act
HttpResponseMessage response;
response = await _client.PostAsync($"/api/librarian", form);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
我遇到的几个问题是添加 stringContent 并确保正确命名文件和字符串内容,以便控制器可以映射值。