Search code examples
c#unit-testingconfigurationstartup

How can I mock or set up values for a unit test that are normally set to a static property in startup?


In our project there's a class with a bunch of static fields that is used to hold setting values in memory:

public class MyConfigurationSettings
{
    public static string MySettingId { get; set; }
    
    public string MySettingProcessIdentifier
    {
        get { return MySettingId; }

        set { MySettingId = value; }
    }
}

I'm not sure why it's like this - that's lost to the mists of time. This object is populated from a settings file in startup.

var defaultConfiguration = new MyConfigurationSettings();
configuration.GetSection("MyConfiguration").Bind(defaultConfiguration);

However, I now need to write a unit test that's dependent on these values. The object is available to my tests:

TypeId = MyConfigurationSettings.MySettingId

But the value is always empty (or zero for an int) and most of the tests need to check which setting value the code is using.

I had a look at using ConfigurationBuilder but the only useful option seemed to be to load a json file, which isn't really ok for a unit test, and I'm not sure how to bind it.

How can I populate this object for a unit test?


Solution

  • When your project starts, there should be a root defined somewhere, which tells the app where to look for appsettings.json (I assume you use it, as long as you are talking about configuration). E.g.:

    var builder = new ConfigurationBuilder()
                    .SetBasePath(env.ContentRootPath)
                    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    

    When you run the tests your execution directory is different and file is not loaded. So you can:

    • set values in the test constructor (it's a static object with getters and setter)
    • point to the right file json file when your test project starts, path will be different
    • use, as proposed in the comments, and what I would personally consider a good refactoring, the way with DI and IOptions. In that case you could just inject the settings that you want into the class that you test.

    You register your settings in Startup:

    services.Configure<MySettings>(this.Configuration.GetSection("MySettings"));
    

    In you class in constructor use DI:

    public class MyClass{
     public MyClass(IOptions<MySettings> settings) { ... }
    }
    

    In your test:

    new MyClass(Options.Create<MySettings>(new MySettings(/* test settings here */)))