集成测试 multipart/form-data c#

Spy*_*Spy 2 c# integration-testing web-api-testing asp.net-core asp.net-core-webapi

我在尝试为我的后调用创建一个集成测试时遇到了麻烦,该测试接受一个具有其他值的视图模型,一个 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;
        } 
Run Code Online (Sandbox Code Playgroud)

我的测试方法

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);
        }
Run Code Online (Sandbox Code Playgroud)

我的控制器方法

[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();
        }
Run Code Online (Sandbox Code Playgroud)

它会抛出 BadRequest 而无需进入该方法。

Che*_*iya 5

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

当 API 期望FileInfo请求负载中包含 a 时,发布 JSON 内容永远不会起作用。您需要以 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; }
}
Run Code Online (Sandbox Code Playgroud)

这与您的 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);
Run Code Online (Sandbox Code Playgroud)

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

控制台输出

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

API调试捕获

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

邮递员捕获

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