使用 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 并确保正确命名文件和字符串内容,以便控制器可以映射值。