【问题标题】:Integration Testing multipart/form-data c#集成测试 multipart/form-data c#
【发布时间】:2021-07-01 13:46:23
【问题描述】:

我在尝试为我的 post call 创建一个集成测试时遇到了麻烦,该测试接受一个 viewmodel,其中包含一个 IFormFile,它使这个调用从 application/json 到 multipart/form-data

我的 IntegrationSetup 类

protected static IFormFile GetFormFile()
        {
            byte[] bytes = Encoding.UTF8.GetBytes("test;test;");

            var file = new FormFile(
                baseStream: new MemoryStream(bytes),
                baseStreamOffset: 0,
                length: bytes.Length,
                name: "Data",
                fileName: "dummy.csv"
            )
            {
                Headers = new HeaderDictionary(),
                ContentType = "text/csv"
            };

            return file;
        } 

我的测试方法

public async Task CreateAsync_ShouldReturnId()
        {
            //Arrange
            using var content = new MultipartFormDataContent();
            var stringContent = new StringContent(
                JsonConvert.SerializeObject(new CreateArticleViewmodel
                {
                    Title = "viewModel.Title",
                    SmallParagraph = "viewModel.SmallParagraph",
                    Url = "viewModel.Url",
                    Image = GetFormFile()
                }),
                Encoding.UTF8,
                "application/json");
            stringContent.Headers.Add("Content-Disposition", "form-data; name=\"json\"");
            content.Add(stringContent, "json");

            //Act
            var response = await httpClient.PostAsync($"{Url}", content);
            //Assert
            response.StatusCode.ShouldBe(HttpStatusCode.OK);
            int id = int.Parse(await response.Content.ReadAsStringAsync());
            id.ShouldBeGreaterThan(0);
        }

我的控制器方法

[HttpPost]
        public async Task<IActionResult> CreateArticleAsync([FromForm] CreateArticleViewmodel viewModel)
        {

            var id = await _service.CreateAsync(viewModel).ConfigureAwait(false);
            if (id > 0)
                return Ok(id);
            return BadRequest();
        }

它在没有进入方法的情况下抛出一个 BadRequest。

【问题讨论】:

  • 你不应该使用application/json content-type。
  • 我尝试过使用 multipart/form-data 但我得到了相同的结果。

标签: c# asp.net-core integration-testing asp.net-core-webapi web-api-testing


【解决方案1】:

您在代码中将请求内容发布到 API 的方式不正确。

当 API 需要在请求负载中包含 FileInfo 时,发布 JSON 内容永远不会起作用。您需要以 MultipartFormData 而不是 JSON 格式发送有效负载。

考虑以下示例。

这是一个 API 端点,它期望并使用其中的 FileInfo 作为有效负载进行建模。

[HttpPost]
public IActionResult Upload([FromForm] MyData myData)
{
    if (myData.File != null)
    {
        return Ok("File received");
    }
    else
    {
        return BadRequest("File no provided");
    }
}

public class MyData
{
    public int Id { get; set; }
    public string Title { get; set; }
    // Below property is used for getting file from client to the server.
    public IFormFile File { get; set; }
}

这与您的 API 几乎相同。

以下是客户端代码,它使用文件和其他模型属性调用上述 API。

var apiURL = "http://localhost:50492/home/upload";
const string filename = "D:\\samplefile.docx";

HttpClient _client = new HttpClient();

// Instead of JSON body, multipart form data will be sent as request body.
var httpContent = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(File.ReadAllBytes(filename));
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");

// Add File property with file content
httpContent.Add(fileContent, "file", filename);

// Add id property with its value
httpContent.Add(new StringContent("789"), "id");

// Add title property with its value.
httpContent.Add(new StringContent("Some title value"), "title");

// send POST request.
var response = await _client.PostAsync(apiURL, httpContent);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();

// output the response content to the console.
Console.WriteLine(responseContent);

客户端代码从控制台应用程序运行。因此,当我运行此程序时,期望在控制台中收到 File received 消息,而我正在收到该消息。

以下是调试时 API 端模型内容的屏幕截图。

如果我从邮递员那里调用这个 API,它会如下所示。

希望这能帮助您解决问题。

【讨论】:

  • 它就是这样工作的。我认为你必须分解视图模型并将每个字段添加到内容而不是我想要做的事情,这很奇怪,当你有“简单”值类型,如“int”,string,“decimal”, bool”等可能是因为所有内容都被视为字符串。
  • 当数据作为多部分表单数据发送时,需要单独添加为表单字段...如果主模型中有类属性,您也可以发送复杂数据。
猜你喜欢
  • 2012-09-17
  • 2018-03-30
  • 2019-12-03
  • 1970-01-01
  • 2021-04-22
  • 2011-03-17
  • 2015-09-19
  • 2013-12-10
  • 1970-01-01
相关资源
最近更新 更多