I'm using:
- Visual Studio 2017 Pro
- dotnet core sdk 2.2.102
- XUnit 2.4.1
What I'm trying to do
Integration test an API Controller Method that accepts Form Data.
Setup
- API route in my controller that accepts a CommandObject using the [FromForm]attribute
- One of the properties of the CommandObject is of type List<IFormFile>, this is designed to manage any files that are part of the request
- The Controller method works as expected when I test it manually from Postman.
The Problem
The Files are not bound to the List<IFormFile> property.  Everything else works as expected, but the files do not.  The is the first time I've used Multipart Form Data, so am not sure what to try.
When I debug the test, you can see everything works except for the Documents property (Note, this doesn't match 100% with the code below, because I've had to obfuscate some stuff)
Stuff I've looked at
There is a lot of stuff relating to multipart form data, some of the solutions I've tried are:
MyIntegrationTest.cs
There's a lot of code behind the setup of my integration tests.  If I post it all here I don't think it will be very helpful.  The most important piece of information is that variable server is of type Microsoft.AspNetCore.TestHost.TestServer
[Fact]
async Task Post_ItemAsync_HappyPath_ReturnsOKStatusCode()
{
    var fileDir = @"C:/path/to/files";
    var fileNames = new string[] { "test.docx", "test.txt" };
    using (var server = CreateTestServer())
    {
        // Arrange
        var formData = new MultipartFormDataContent()
        {
            { new StringContent("Test Title"), "Title" },
            { new StringContent("Test Description"), "Description" },
            { new StringContent("String_1"), "AListOfStrings" },
            { new StringContent("String_2"), "AListOfStrings" },
            { new StringContent("3"), "NumberOfThings" }
        };
        foreach (var fileName in fileNames)
        {
            var document = File.ReadAllBytes($"{fileDir}/{fileName}");
            formData.Add(new ByteArrayContent(document), "file", fileName);
        }
        string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid());
        string contentType = "multipart/form-data; boundary=" + formDataBoundary;
        var request = new HttpRequestMessage(HttpMethod.Post, "api/v1/item")
        {
            Headers =
            {
                { HttpRequestHeader.ContentType.ToString(), contentType }
            },
            Content = formData
        };
        // Act
        var response = await server.CreateClient().SendAsync(request);
        // Assert
        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        // Cleanup
        ...
    }
}
MyController.cs
[HttpPost]
ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> CreateItemAsync([FromForm]CreateItemCommand command)
{
    bool commandResult = false;
    commandResult = await _mediator.Send(command);
    if (!commandResult)
    {
        return BadRequest();
    }
    return Ok();
}
CreateItemCommand.cs
[DataContract]
public class CreateItemCommand
    :IRequest<bool>
{
    [DataMember]
    public string Title { get; set; }
    [DataMember]
    public string Description { get; set; }
    [DataMember]
    public HashSet<string> AListOfThings { get; set; }
    [DataMember]
    public int NumberOfThings { get; set; }
    [DataMember]
    public List<IFormFile> Documents { get; private set; }
    public CreateITemCommand()
    {
        AListOfThings = new HashSet<string>();
    }
    public CreateItemCommand(string title, string description, HashSet<string> aListOfThings, int NumberOfThings, List<IFormFile> documents)
        : this()
    {
        Title = title;
        Description = description;
        AListOfStrings = aListOfStrings;
        NumberOfThings = numberOfThings;
        Documents = documents;
    }
}

 
    