One new feature of .NET Core is the built-in dependency injection container. Specifically, within the Configure Services method of the startup, you can easily configure options models. I like to leverage an AppSettings helper model to pass my settings around my application, but while doing so, I still need a way to easily break my dependencies for unit testing.
Background
To achieve the set up of having an AppSettings model being passed around the application, you need to create the app settings in your actual appsettings.json, have it match the model, and configure it within the start up. After doing so, you can pass in an IOptions<T> to a class and it will resolve correctly.
In appsettings.json:
{ "AppSettings": { "ApplicationName": "My Test App", "DefaultTimeout": 60 } }
The AppSettings class:
public class AppSettings { public string ApplicationName { get; set; } public int DefaultTimeout { get; set; } }
In Startup.cs:
public void ConfigureServices(IServiceCollection services) { services.Configure<AppSettings>(Configuration.GetSection("AppSettings")); }
Now, usage is as follows:
public class ValuesController { public ValuesController(IOptions<AppSettings> appSettingsOptions) { var appSettings = appSettingsOptions.Value; //appSettings.ApplicationName = "My Test App" //appSettings.DefaultTimeout = 60 } }
Unit Testing
Now we get to the real problem. I don’t have a dependency injection container strictly for my unit testing, so I can’t instantiate a ValuesController that is using the IOptions<AppSettings>. I could try to set one up, but that’s definitely overkill for just being able to use some settings. Luckily, there is a way to manually create an instance of an IOptions<T>, using the Options.Create() method.
So, building up my dependency looks like this:
var settings = new AppSettings(){ ApplicationName = "Test Project", DefaultTimeout = 15 }; IOptions<AppSettings> appSettingsOptions = Options.Create(settings); var valuesController = new ValuesController(appSettingsOptions); //Actually test ValuesController here
I originally encountered this issue while attempting to leverage a service that was using IOptions
Hi,
Is there any way we can do the same for IOptionsMonitor ?
Thanks
Thanks, Mitch. This really helped me.
Thanks
Thanks Mitch, this really hit the problem right on the head and helped out a ton.
Thanks Mitch, this one was puzzling me
Just what I was looking for! Thanks.
Couldn’t you use FakeItEasy to fake the ValuesController’s dependency from IOptions in your unit tests?
Yeah definitely, and if that’s what you prefer to do, there’s nothing wrong with that. This way doesn’t require adding a dependency to FakeItEasy though.
Cheers Mitch. Had exactly the same issue. Thanks!