How to write functional tests for ASP.NET Core API


We have an ASP.NET core API and want to write tests covering the API functionality:

  • Test responses from endpoints when things work as expected
  • Test cases when things go wrong and

When an API uses environment variables for configuration

// Create environment variables for the test process
// Depending on the test framework used, this is done when the test starts. e.g. a constructor in xUnit or a method annottated with [Setup] in NUnit
var inMemoryEnvironmentVariables = new Dictionary<string, string>
    { "baseUrl", "" },
    { "someOtherConfig", "value" }

foreach (var variable in inMemoryEnvironmentVariables) 
    Environment.SetEnvironmentVariable(variable.Key, variable.Value);

Create a WebHostBuilder and a TestServer to host the API in-memory

// using Microsoft.AspNetCore.Hosting
var builder = new WebHostBuilder()
                    configurationBuilder =>             configurationBuilder.AddEnvironmentVariables(prefix: "WHATEVER_"))

// using Microsoft.AspNetCore.TestHost;
var testServer = new TestServer(builder);
var httpClient = testServer.CreateClient();

// use httpClient to call the API hosted in memory

How To inject mocked external services

// Use NSubstitute to create a mock
_mockService = Substitute.For<ISomeService>();

var builder = new WebHostBuilder()
                    serviceCollection => serviceCollection.AddScoped<ISomeService>(
                        provider => _mockService))
                .ConfigureAppConfiguration(configurationBuilder => configurationBuilder.AddEnvironmentVariables(prefix: "SOMETHING_"))

Making EF Core based DbContext testable

  • Use a class that looks like the following to model your DbContext
public class ApplicationDbContext : DbContext
    public DbSet<SomeModel> SomeModels { get; set; }

    public ApplicationDbContext() { }

    // This constructor facilitates testability 
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options): base(options)

    protected override void OnModelCreating(ModelBuilder builder)

    public override int SaveChanges()
        int result = base.SaveChanges();

        return result;
  • In the test fixture, use the strategy outlined in MS Docs
    • Add the nuget package Microsoft.EntityFrameworkCore.InMemory
public class MyRepositoryShould
    public void BehaveAsXXX_WhenGivenYYYY()
        // create DbContextOptions
        var options = new DbContextOptionsBuilder<ApplicationDbContext>()
                .UseInMemoryDatabase(databaseName: "Scenario")
        // Add some data
        using (var context =  new ApplicationDbContext(options))
            context.SomeModels.Add(new SomeModel {//properties});
        // now inject a new instance of context in your repository