2

We have recently added Azure App Configuration into our Azure Functions, and we now want the Startup code for the App Configuration to be triggered via the tests.

Our function startup code looks like this -

    public override void Configure(IFunctionsHostBuilder builder)
    {
        config = Utils.LoadConfig();
        StartupHelper.AddCommonIoCDependencies(builder);
    }

    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
        //How do we trigger this method when testing???
        StartupHelper.AddAzureAppConfiguration(builder);
    }

The initial configure method is triggered when running tests by using the following -

    private MyFunction_sut;

    [SetUp]
    public void Setup()
    {
        var funcStartup = new Startup();

        var host = new HostBuilder()
            .ConfigureWebJobs(funcStartup.Configure)
            .Build();

        _sut = new MyFunction(...);
    }

This works for triggering the Congfigure method. And despite the HostBuilder having options for ConfigureAppConfiguration, I can't figure out how to get this working. I feel there should be a quick and easy way with what I've put below.

            var host = new HostBuilder()
            .ConfigureWebJobs(funcStartup.Configure)
            .ConfigureAppConfiguration(x => {
                //What do I put here to call trigger the ConfigureAppConfiguration method at startup?
                //Or is it possible to call my helper "AddAzureAppConfiguration" method that is in a static class?
            })
            .Build();

If there's a different way to test Azure Functions to add in Azure App Configuration that doesn't involve HosatBuilder then I'd love to hear other people's approaches. I really can't see much for this when googling online, so I feel like I'm missing something.

Any advice is appreciated!

user3407039
  • 1,285
  • 5
  • 25
  • 51
  • Have you referred to https://learn.microsoft.com/en-us/azure/azure-app-configuration/quickstart-azure-functions-csharp? – Jim Xu Jun 01 '21 at 01:05
  • Yes I've been through all the official documentation I can find. There is nothing on the page you linked for how best to test Azure App Configuration setup that I can see. – user3407039 Jun 01 '21 at 07:41
  • I can't get it working in my environment - it keeps loading the wrong values, but I think that is my configuration issue in Rider - this shows you how to trigger the call to ConfigureAppConfiguration. https://learn.microsoft.com/en-us/answers/questions/206591/create-xunit-test-for-configureappconfiguration.html – RichS Aug 14 '21 at 06:50

2 Answers2

6

I needed to do something similar. Unfortunately the implementation of IFunctionsConfigurationBuilder, which is needed to accomplish this, is marked internal so I had to duplicate the implementation myself. Thankfully it is simple.

// https://github.com/Azure/azure-functions-dotnet-extensions/blob/main/src/Extensions/DependencyInjection/FunctionsConfigurationBuilder.cs
internal class FunctionsConfigurationBuilder : IFunctionsConfigurationBuilder
{
    public FunctionsConfigurationBuilder(IConfigurationBuilder configurationBuilder, WebJobsBuilderContext webJobsBuilderContext)
    {
        ConfigurationBuilder = configurationBuilder ?? throw new ArgumentNullException(nameof(configurationBuilder));
        Context = new DefaultFunctionsHostBuilderContext(webJobsBuilderContext);
    }

    public IConfigurationBuilder ConfigurationBuilder { get; }

    public FunctionsHostBuilderContext Context { get; }
}

// https://github.com/Azure/azure-functions-dotnet-extensions/blob/main/src/Extensions/DependencyInjection/DefaultFunctionsHostBuilderContext.cs
internal class DefaultFunctionsHostBuilderContext : FunctionsHostBuilderContext
{
    public DefaultFunctionsHostBuilderContext(WebJobsBuilderContext webJobsBuilderContext)
        : base(webJobsBuilderContext)
    {
    }
}

This allows me to setup my testing like this:

public TestHost()
{
    var webJobsBuilderContext = new WebJobsBuilderContext();
    var startup = new TestStartup();
    var host = new HostBuilder()
        .ConfigureAppConfiguration((context, builder) =>
            startup.ConfigureAppConfiguration(new FunctionsConfigurationBuilder(builder, webJobsBuilderContext))
        )
        .ConfigureWebJobs((context, builder) =>
        {
            webJobsBuilderContext.Configuration = context.Configuration;
            startup.Configure(webJobsBuilderContext, builder);
        })
        .Build();

    ServiceProvider = host.Services;
}

public IServiceProvider ServiceProvider { get; }

And the Startup for my tests looks like:

private class TestStartup : Startup
{
    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
        // Do anything else you need to here
        base.ConfigureAppConfiguration(builder);
    }

    public void Configure(WebJobsBuilderContext context, IWebJobsBuilder builder)
    {
        // Do anything else you need to here
        base.Configure(context, builder);
    }
}

That's pretty much it. Let me know if further details are needed. It's not straightforward unfortunately.

chris
  • 2,740
  • 3
  • 25
  • 23
1

There is a ConfigureWebJobs extension method overload you can use to do this:

public static IHostBuilder ConfigureWebJobs(this IHostBuilder builder,
    Action<HostBuilderContext,
    IWebJobsBuilder> configure,
    Action<JobHostOptions> configureOptions,
    Action<HostBuilderContext, IWebJobsConfigurationBuilder> configureAppConfiguration)

You can trigger your ConfigureAppConfiguration by calling UseWebJobsConfigurationStartup on the configureAppConfiguration parameter like this:

var webJobsBuilderContext = new WebJobsBuilderContext();

var host = new HostBuilder()
    .ConfigureWebJobs((context, builder) =>
    {
        builder.UseWebJobsStartup(typeof(TestStartup), webJobsBuilderContext, NullLoggerFactory.Instance);
    }, _ => { }, (context, builder) =>
    {
        builder.UseWebJobsConfigurationStartup<TestStartup>(webJobsBuilderContext);
    })
    .Build();
David Naylor
  • 56
  • 1
  • 4