File uploads in ASP.NET Core integration tests

Writing integration tests for ASP.NET Core controller actions used for file uploads is not a rare need. It is fully supported by ASP.NET Core integration tests system. This post shows how to write integration tests for single and multiple file uploads.

Getting started

Suppose we have controller action for file upload that supports multiple files. It uses complex composite command for image file analysis and saving. Command is injected to action by framework-level dependency injection using controller action injection.

[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Upload(IList<IFormFile> files, int? parentFolderId,
                                        [FromServices]SavePhotoCommand savePhotoCommand)
{
    foreach(var file in files)
    {
        var model = new PhotoEditModel();
        model.FileName = Path.GetFileName(file.FileName);
        model.Thumbnail = Path.GetFileName(file.FileName);
        model.ParentFolderId = parentFolderId;
        model.File = file;

        list.AddRange(savePhotoCommand.Validate(model));

        await savePhotoCommand.Execute(model);
    }

    ViewBag.Messages = savePhotoCommand.Messages;

    return View();
}

We want to write integration tests for this action but we need to upload at least one file to make sure that command doesn’t fail.

Making files available for integration tests

It’s good practice to have files for testing available no matter where tests are run. It’s specially true when writing code in team or using continuous integration server to run integration tests. If we don’t have many files and the files are not large then we can include those files in project.

Important thing is to specify in Visual Studio that these files are copied to output folder.

ASP.NET Core: Files delivered to integration tests folder

Same way it’s possible to use also other types of files and nobody stops us creating multiple folders or folder trees if we want to organize files better.

Uploading files in integration tests

Here is integration tests class for controller mentioned above. Right now there’s only one test and it is testing Upload action. Notice how image files are loaded from TestPhotos folder to file streams and how form data object is built using the file streams.

public class PhotosControllerTests : IClassFixture<WebApplicationFactory<Startup>>
{
    private readonly WebApplicationFactory<Startup> _factory;

    public PhotosControllerTests(WebApplicationFactory<Startup> factory)
    {
        _factory = factory;
    }

    [Fact]
    public async Task Upload_SavesPhotoAndReturnSuccess()
    {
        // Arrange
        var expectedContentType = "text/html; charset=utf-8";
        var url = "Photos/Upload";
        var options = new WebApplicationFactoryClientOptions { AllowAutoRedirect = false };
        var client = _factory.CreateClient(options);

        // Act
        HttpResponseMessage response;

        using (var file1 = File.OpenRead(@"TestPhotos\rt-n66u.jpg"))
        using (var content1 = new StreamContent(file1))
        using (var file2 = File.OpenRead(@"TestPhotos\speedtest.png"))
        using (var content2 = new StreamContent(file2))
        using (var formData = new MultipartFormDataContent())
        {
            // Add file (file, field name, file name)
            formData.Add(content1, "files", "rt-n66u.jpg");
            formData.Add(content2, "files", "speedtest.png");

            response = await client.PostAsync(url, formData);
        }

        // Assert
        response.EnsureSuccessStatusCode();
        var responseString = await response.Content.ReadAsStringAsync();

        Assert.NotEmpty(responseString);
        Assert.Equal(expectedContentType, response.Content.Headers.ContentType.ToString());

        response.Dispose();
        client.Dispose();
    }
}

For actions that accept only one file we need only one call to Add() method of formData.

Need authenticated user for integration tests? Head over to my blog post Using ASP.NET Core Identity user accounts in integration tests.

Wrapping up

Integration tests mechanism in ASP.NET Core is flexible enough to support also more advanced scenarios like file uploads in tests. It’s not very straightforward and we can’t just call few methods of HTTP client to do it but it’s still easy enough once we know the tricks. If we keep test files in integration tests project then we don’t have to worry about getting files to machine where integration tests are running.

Gunnar Peipman

Gunnar Peipman is ASP.NET, Azure and SharePoint fan, Estonian Microsoft user group leader, blogger, conference speaker, teacher, and tech maniac. Since 2008 he is Microsoft MVP specialized on ASP.NET.

    9 thoughts on “File uploads in ASP.NET Core integration tests

    • November 26, 2019 at 12:40 pm
      Permalink

      Hello Gunnar,

      Nice example for testing the controller, but how would you test the SavePhotoCommand in isolation? Assuming that PhotoEditModel.File is of type IFormFile, I don’t think it’s possible.

      All the best,

      Steven

    • January 2, 2022 at 6:26 pm
      Permalink

      Hi,
      Thanks for the Example.
      When debugging I get in the post API that the Ifiles list have null in content type property.
      Can you please advise how to fix it? in my app it is necessary.
      Thanks a lot,
      Yossi

    • April 20, 2025 at 1:59 am
      Permalink

      Secure srlf stoage іn Worthing ffor caravans,
      cars, аnd motorhomes. Arrun Ѕelf Storfage offfers
      affordable solutions іn Littlehampon Marina.

    • April 24, 2025 at 2:45 am
      Permalink

      Thank you for any other informative web site. The place else may I am getting that
      kind of info written in such a perfect manner?
      I’ve a undertaking that I’m just now working on, and I’ve been at the glance
      out for such info.

    • April 24, 2025 at 6:47 pm
      Permalink

      Every weekend i used to visit this website, because i wish for enjoyment, since this this web site conations genuinely nice funny
      information too.

    • April 25, 2025 at 5:57 am
      Permalink

      Today, while I was at work, my sister stole my iphone and tested to see
      if it can survive a forty foot drop, just
      so she can be a youtube sensation. My apple ipad is now destroyed and she has 83 views.
      I know this is totally off topic but I had to share it with someone!

    • April 27, 2025 at 4:23 pm
      Permalink

      First of all I would like to say terrific blog! I had a
      quick question in which I’d like to ask if you don’t
      mind. I was curious to know how you center yourself and clear your thoughts prior to writing.
      I have had difficulty clearing my mind in getting my ideas out there.
      I truly do enjoy writing but it just seems like the first 10 to 15 minutes are usually lost just trying to figure
      out how to begin. Any recommendations or tips? Kudos!

    • May 3, 2025 at 6:28 pm
      Permalink

      We absolutely love your blog and find a lot of your post’s to be just what I’m looking for.

      can you offer guest writers to write content to suit your needs?

      I wouldn’t mind writing a post or elaborating on most of the subjects you
      write related to here. Again, awesome site!

    Leave a Reply

    Your email address will not be published. Required fields are marked *