I pass IOption<T>
to my CommandBus
so I can get the settings from my ServiceBusSetting
class. I want to do an integration test of my Bus. I do not want to resolve it just use new QueueCommandBus
and need to pass IOptions
to it.
var services = new ServiceCollection().AddOptions();
services.Configure<ServiceBusAppSettings>(Configuration.GetSection("ServiceBus"));
var options = services.BuildServiceProvider().GetService<IOptions<ServiceBusAppSettings>>();
////Act
var commandBus = new QueueCommandBus(options);
This works fine, but feels very complex code to get the IOptions<T>
from my appsetting.json
in my test project.
Any clue if this is the only way or is there a better way?
IOptionsMonitor is a Singleton service that retrieves current option values at any time, which is especially useful in singleton dependencies. IOptionsSnapshot is a Scoped service and provides a snapshot of the options at the time the IOptionsSnapshot<T> object is constructed.
Integration tests ensure that an app's components function correctly at a level that includes the app's supporting infrastructure, such as the database, file system, and network. ASP.NET Core supports integration tests using a unit test framework with a test web host and an in-memory test server.
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.
You don't need to create the ServiceCollection
or IServiceProvider
. The IConfiguration
interface has a Bind()
method, or from .NET Core 1.1 onwards, Get<T>
which you can use to get the strongly-typed object directly:
var config = Configuration.GetSection("ServiceBus");
// .NET Core 1.0
var options = new ServiceBusAppSettings();
config.Bind(options);
// .NET Core 1.1
var options = config.Get<ServiceBusAppSettings>();
I like to add these as static methods to my AppSettings
strongly-typed object, to make it convenient to load them from JSON in both my web app and from unit tests.
AppSettings.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
namespace My.Namespace
{
public class AppSettings
{
public class ServiceBusAppSettings
{
public string Setting1;
public int Setting2;
}
public class ApiSettings
{
public bool FormatJson { get; set; }
}
public class MySqlSettings
{
public string User { get; set; }
public string Password { get; set; }
public string Host { get; set; }
public string Database { get; set; }
public int Port { get; set; } = 3306;
public string GetConnectionString()
{
return $"Server={Host};Database={Database};Port={Port};Uid={User};Pwd={Password}";
}
}
public ServiceBusAppSettings ServiceBus { get; set; } = new ServiceBusAppSettings();
public ApiSettings Api { get; set; } = new ApiSettings();
public MySqlSettings MySql { get; set; } = new MySqlSettings();
// Static load helper methods. These could also be moved to a factory class.
public static IConfigurationRoot GetConfiguration(string dir)
{
return GetConfiguration(dir, null);
}
public static IConfigurationRoot GetConfiguration(string dir, string environmentName)
{
if (string.IsNullOrEmpty(environmentName))
environmentName = "Development";
var builder = new ConfigurationBuilder()
.SetBasePath(dir)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{environmentName}.json", true)
.AddEnvironmentVariables();
return builder.Build();
}
public static AppSettings GetSettings(string dir)
{
return GetSettings(dir, null);
}
public static AppSettings GetSettings(string dir, string environmentName)
{
var config = GetConfiguration(dir, environmentName);
return GetSettings(config);
}
public static AppSettings GetSettings(IConfiguration config)
{
return config.Get<AppSettings>();
}
}
}
ASP.NET Core Startup.cs
: (Getting the strongly-typed settings object is often helpful at this stage, when configuring the other services...)
public class Startup
{
public Startup(IHostingEnvironment env)
{
Configuration = AppSettings.GetConfiguration(env.ContentRootPath, env.EnvironmentName);
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Configure the service collection.
services.AddOptions();
services.Configure<AppSettings>(Configuration);
// It can also be handy to get the AppSettings object here.
var settings = AppSettings.GetSettings(Configuration);
// Add framework services.
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
// Pretty-print JSON in Development
options.SerializerSettings.Formatting = settings.Api.FormatJson ? Formatting.Indented : Formatting.None;
});
// Store DB connection info in AppSettings too...
var conn = settings.MySql.GetConnectionString();
services.AddDbContext<MyDbContext>(opt => opt.UseMySql(conn));
}
}
In Test Class:
var testDir = AppContext.BaseDirectory;
var settings = AppSettings.GetSettings(testDir, "Test");
//Act
var commandBus = new QueueCommandBus(settings);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With