Unit test SerializableConfigurationSection programmatically - c#

I'm using strongly typed configuration sections in my project and want to unit test a particular area which throws an exception when a setting isn't set-up correctly.
A snippet of the configuration class:
public class EmailSettings : SerializableConfigurationSection, IEmailSettings
{
[ConfigurationProperty("from", IsRequired = true)]
public string From
{
get
{
...
}
set
{
...
}
}
...
}
Sample test method:
[TestMethod]
public void something_describing_this_test()
{
EmailSettings settings = new EmailSettings();
settings.From;
}
I expect that SerializableConfigurationSection and its inners are looking for a web.config (or similar) to read xml config from.
How can I get in the middle and 'mock' the configuration to enable me to pipe custom values to test for certain conditions? This question (using ConfigurationManager methods) appears to do it via a physical config file in the assembly - is this the only way or can I get in there programmatically?

You could generate one in your test fixture setup, and then load it like described in the answer to this question:
Loading custom configuration files

Related

Issue understanding a behaviour linked to appsettings binding in .NET Core

I'm facing a weird issue where I can't seem to bind appsettings values from my appsettings.Development.json file using Configuration.Get<T>().
I've done it countless times on different project in the exact same way but apparently "not this time".
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var myConfig = Configuration.Get<MySettingType>();
}
}
Usually this works perfectly.
I left the Program.cs clean from any edit that could change the default behaviour regarding loading the appsettings files.
MySettingType is the same name as the key in the appsettings file, matching class is using properties, all public.
The configuration is at the root of the json file as well.
What happened is that the code would only lead to null values being filled in the myConfig object.
Now I solved the issue using this code instead of Configuration.Get<T>():
var myConfig = new MySettingType();
Configuration.GetSection(nameof(MySettingType)).Bind(myConfig);
This is all cool, but the question is why did I have to use that?
What could explain it?
I would always include a GetSection. Something like this:
Configuration.GetSection(nameof(MySettingType)).Get<MySettingType>();
But do you really need the myConfig later in your ConfigureServices method?
If not, you can also do this:
services.Configure<MySettingType>(Configuration.GetSection(nameof(MySettingType));
You can find different examples of how Microsoft suggest to bind hierarchical configuration.
When binding options, it is assumed that the structure of T will be the same as whatever the Configuration is. It does not take the type name into account. So if you want to bind the options from a specific part of the configuration keyed by your type, you'll need to use GetSection which will return a new ConfigurationSection object scoped to that section. Then the same rules apply since.
If you want a convention, you could write an extension method that could bind based on type names for you.
public static T BindByTypeName<T>(this IConfiguration configuration)
where T : class, new()
{
return configuration.Bind<T>(typeof(T).Name);
}
You could also wrap MySettingsType with another AppSettings or something so that your options match your appsettings.json structure.
class AppSettings
{
public MySettingsType MySettingsType { get; set; }
}
Then you can simply call Get<AppSettings> on the root configuration.
Configuration.Get<AppSettings>().MySettingsType;

C#: Run each unit test with different configuration file

I'm currently developing a plugin to use in any application, and the configuration of the plugin is done through the usage of either a web.config or an app.config file.
Now, I want to unit test my plugin. I want to test the different behaviour in various conditions:
For exmaple:
Only 1 single item should be marked as 'default'.
A collection of providers can be registered in the plugin, however the name must be unique, otherwise, a specific exception is thrown.
My question:
I have a unit test project and I want to test each method with another application configuration file, is this possible?
I've tried reading the file from ExeConfiguration, but I don't get it to work.
Thanks for the feedback.
Kr,
This is what we do (same as #THG) explained in his answer.
public interface IConfiguration
{
string SettingA { get; }
string SettingB { get; }
}
public class Configuration : IConfiguration
{
public string SettingA
{
get
{
return ConfigurationManager.AppSettings["SettingA"];
}
}
public string SettingB
{
get
{
return ConfigurationManager.AppSettings["SettingB"];
}
}
}
Then in your test
var config = MockRepository.GenerateStub<IConfiguration>();
config.Stub(x => x.SettingA).Return("Fred");
My recommendation is to mock the integration with the config file instead of using it directly. This approach offers much more flexibility and removes the need to worry about multiple config files.
You can either use a mocking framework or create you own layer of abstraction on top of the code that fetches the config values.

How can I horribly twist a c# project to read its class library's app.config files

So let me start off by saying "I know this isn't a best practice" and that I do not want to add the information from the app.config files to the web.config file... I've got a project that is a class library itself and it will be using a lot of class libraries as well.
Typically in my unit test project (used for testing) or my web project (that uses the lib in production) I have to add all of the configuration information. These libraries aren't going to be called differently from each project so I'm looking for a way to get the calling project to read the callee project's config file.
I've looked online and the only two things I've found so far are:
1) Don't do it. You need to add the information to the calling project's config file
example a) Read from App.config in a Class Library project
example b) Class Library project in ASP.NET reading from web.config and not app.config
example c) .Net app.config in library project
2) You shouldn't do it but I know how (no how to included :/)
example a) app.config for a class library
I've been doing it the "right" way for a while and that has left me with lots of web.config and test project config files with info duplicated from class lib app.config files. I really do think that there is a specific, justified use case for doing this.
Thanks!
The best practice that I know of is to avoid direct dependency on app.config/web.config from classes in your library, or maybe even classes in general. That doesn't mean that you don't use app.config. It means that your classes don't know they're using it.
For example,
public class MyClassThatDependsOnSomeSettings
{
private readonly ISettings _settings;
public MyClassThatDependsOnSomeSettings(ISettings settings)
{
_settings = settings;
}
public void DoSomething()
{
var settingA = _settings.SettingA;
}
}
public interface ISettings
{
int SettingA {get;}
string SettingB {get;}
}
Now you can consider MyClassThatDependsOnSomeSettings done. It doesn't require any access to a .config file. It just requires an instance of something that implements ISettings. That can read from .config.
public class SettingsFromConfiguration : ISettings
{
public int SettingA
{
get
{
string setting = ConfigurationManager.AppSettings["settingA"];
int value = 0;
int.TryParse(setting, out value);
return value;
}
}
public string SettingB
{
get { return ConfigurationManager.AppSettings["settingB"];}
}
}
Does it look like this just moves things around and does the same thing anyway? It does, almost. The big difference is that while you can use an implementation of ISettings that reads from app.config, you can also write other implementations. You can write one that uses hard-coded values, you could write a custom configuration section instead of using AppSettings, or if down the road you have an application with a JSON configuration file and no AppSettings your class can still work.
This applies the Dependency Inversion, which beneath everything means that classes should depend on abstractions (like interfaces) not concrete implementations.
Putting a requirement for ISettings in the constructor is called Dependency Injection, specifically constructor injection.

App.config for Xunit

I'm writing some xUnit tests for some helper classes that relies on some configuration settings, usually stored in App.config or Web.config of the executing project.
The config looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="FileNamePattern" value="\\d{8}_\\w{4:20}\.png"/>
<!-- and the likes -->
</appSettings>
</configuration>
I'm running xUnit 1.9 with the GUI runner (xunit.gui.clr4.exe) and xUnit console runner (on the Jenkins CI server). Currently, I can "inject" these configuration values into the test environments by setting the xunit.gui.clr4.exe.config and xunit.console.exe.config files manually); however, this is tedious and error-prone.
I could also mock these configuration settings in a fixture. But using the same fixture across 10 different files is rather repetitive.
Is there a better way to mock these configuration settings with xUnit, such as providing a App.config file for the test project?
If your code assumes they are in the app.config, then xUnit.net supports having them wired up in there by providing one (typically when the tests are in a DLL file, this means you get a AssemblyName.dll.config file in the project outputs which the runner loads as the settings if it exists at load time).
Obviously no harm to use the DI principle to remove such dependencies in the first place, but I'd say don't go messing with code before you actually get it under test first.
To keep it DRY, put the app.config in a central place and add it as a link (via the arrow on the Open button in the dialog). (Yes, there's lots not to like about that - use only if you feel its the least evil approach.)
One thing to look out for is that changes don't get reloaded in the GUI runner unless you ask for the assembly to be reloaded.
From perspective more complex projects & team work, I recommend:
separate .config file for xUnit project (it takes advantage of independent configuration & logging for running tests)
set-up Dependency Injection together with .config reading for xUnit project alone
Our team is using this pattern of xUnit init & dispose:
public class MyTest : IDisposable
{
public IServiceProvider Services { get; private set; }
public MyProjectOptions Options { get; private set; }
public Logger Logger { get; private set; }
private void Configure()
{
// appsettings.workspace.json for custom developer configuration
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.AddJsonFile("appsettings.workspace.json", optional: true)
.Build();
Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.LiterateConsole()
.WriteTo.RollingFile("logs/{Date}-log.txt")
.CreateLogger();
Options = configuration.GetSection("MyProject").Get<MyProjectOptions>();
var services = new ServiceCollection();
services.AddSingleton<ILogger>(s => Logger);
// other DI logic and initializations ...
//services.AddTransient(x => ...);
Services = services.BuildServiceProvider();
}
public MyTest()
{
Configure();
// ... initialize data in the test database ...
var data = Services.GetService<TestDataService>();
data.Clean();
data.SeedData();
}
public void Dispose()
{
// ... clean-up data in the test database ...
var data = Services.GetService<TestDataService>();
data.Clean();
}
}
The solution for me was to name the config file testhost.dll.config, add it to the solution, and set its Copy to Output Directory setting to Copy always.
It has to be named testhost.dll.config because that's how the xUnit component that invokes my tests-project is named. It can be determined as follows:
string invoker = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;
For my setup, invoker turned out to be testhost.dll.

How to configure an object and override that configuration

I have the following interfaces and classes:
public interface ILoggingService { ... }
public class LoggingService {
public LoggingService(ILoggingRepository loggingRepository) { ... }
...
}
public interface ILoggingRepository { ... }
public class DatabaseLoggingRepository {
public DatabaseLoggingRepository(string ConnectionString) { ... }
...
}
public class FileLoggingRepository {
public FileLoggingRepository(string LogFilePath) { ... }
...
}
I'm refactoring my software to use Unity IoC framework and am looking for a way to pass the specific configuration to each ILoggingRepository implementation.
I think that the best way would be to change DatabaseLoggingRepository's and FileLoggingRepository's constructors to have no parameters at all and have them configured by some configuration file. However, because of my acceptance tests I would need a easy way to override these settings while running my tests.
Am I on the right track and if I am, which configuration files should I use? Alternative ways are welcome as well.
What we've decided to do is create a class, in your case it would be LoggingConfiguration, and have that passed to the constructo of the repository. If you resolve using Unity it will instantiate this class using Activator, wuthout having to register it. In your tests however, you just greate a new instance of a derived configuration class, providing different values.
Does it makes sense? Should I clarify more?
Update: I've decided to provide some additional clarification. So, you already have two implementations, and now you want each configuration to query for its proper configuration setting.
I would extend the ILoggingRepository's constructor to look like this:
public ILoggingRepository(ILoggingConfigurationProvider confProvider);
You can then create one implementation for your normal operation which has two properties:
public LoggingConfigurationProvider : ILoggingConfigurationProvider {
public LoggingConfigurationProvider() {
// load both values from configuration file
}
public string LogPath { get; set; }
public string ConnectionString { get; set; }
}
When you instantiate your class via normal IoC operation this will get resolved by the container and you'll configuration options will get loaded from the conf file. When you however want to do Unit tests you:
1) Create a new "Mock" implementation
public class MockLoggingConfigurationProvider : ILoggingConfigurationProvider {
public MockLoggingConfigurationProvider() {
// set both values to a test value
}
public string LogPath { get; set; }
public string ConnectionString { get; set; }
}
Now you can either create the repository using a constructor:
new LoggingRepository(new MockLoggingConfigurationProvider());
or if you want the whole IoC mechanism to be used, you simply (when setting up the container) register this implementation of the interface. Because the unit tests are separate, you don't share the registrations right? So that should give you what you need, the ability to change this settings depending on weather they are being executed as a unit test or not.
In real life, I wouldn't even bother with this, and just create a mock logging repository and have it write somewhere else. Unless you want to test the repository to a test database/file. In which case I'd do as specified.
Hope it helps.
As a design suggestion does not force IoC to deal with configuration stuff. Each logger should manage the configuration the way they prefer in its implementation. IoC should just inject the logger. For the unit/integration test, in both case you should e able to provide a configuration for the logger, for example using log4net I'm used to configure the logging subsystem in the Startup of the test by the api, and I create an appender that write just everithing on the console. You can't Insolate configuration by IoC since each possible logging system does not necessary share a contract for the Configuration part.

Categories