by Jeffrey Palermo via Jeffrey Palermo (.com) on 12/7/2009 2:17:36 PM
All the material I’ve seen talking about reading from .Net configuration files concentrates on explaining the API. The API of ConfigurationManager exposes members such as:
public static class ConfigurationManager { static ConfigurationManager(); public static NameValueCollection AppSettings { get; } public static ConnectionStringSettingsCollection ConnectionStrings { get; } public static object GetSection(string sectionName); public static void RefreshSection(string sectionName); public static Configuration OpenMachineConfiguration(); public static Configuration OpenMappedMachineConfiguration(ConfigurationFileMap fileMap); public static Configuration OpenExeConfiguration(ConfigurationUserLevel userLevel); public static Configuration OpenExeConfiguration(string exePath); public static Configuration OpenMappedExeConfiguration(ExeConfigurationFileMap fileMap, ConfigurationUserLevel userLevel); }
That is a pretty fine-grained API. Every time a developer cracks open that class with intellisense, he is presented with too many choices. Besides that, after getting some functionality working (such as hiding an advanced search criteria based on configuration (for a particular application instance)), the code looks something like this, a jumble of user code and framework call:
public bool ShouldBeVisible(CriteriaName name) { string key = "criterion." + name + ".visible"; string value = ConfigurationManager.AppSettings.Get(key); if (string.IsNullOrEmpty(value)) { return true; } return Convert.ToBoolean(value); }
Given that this code wants to show the criterion by default and let configuration override that, this method needs to be tested. Because of the framework call to configuration, its more difficult to test than necessary. Note, if you aren’t writing automated tests for your code, you probably think I’m crazy right now.
The developer has to run the app three times to ensure this work:
In my experience as a developer and a manager, running the application manually to test these three posibilities takes longer than banging out the three short automated tests for these cases.
There is a problem, through. Because the call to ConfigurationManager (a static class) is embedded in the method, my test code needs to move or modify a REAL configuration file at test time.
The solution: wrap configuration and expose a course-grained interface to may application code. It’s very easy to write your own, but we tend to use the configuration interface defined in the Tarantino project. It’s definition is as follows:
public interface IConfigurationReader { string GetRequiredSetting(string key); int GetRequiredIntegerSetting(string key); bool GetRequiredBooleanSetting(string key); IEnumerable<string> GetStringArray(string key); bool? GetOptionalBooleanSetting(string key); string GetOptionalSetting(string key); }
This may be more than you care to use, so you can trim it down even more very easily. The resulting code is as follows:
public class UiPreferences : IUiPreferences { private readonly IConfigurationReader _reader; public UiPreferences(IConfigurationReader reader) { _reader = reader; } public bool ShouldBeVisible(CriteriaName name) { string key = "criterion." + name + ".visible"; string value = _reader.GetOptionalSetting(key); if (string.IsNullOrEmpty(value)) { return true; } return Convert.ToBoolean(value); } }
Because of the interface, our unit tests are very simple, and the code is simpler as well.
[Test] public void Should_show_criterion_by_default_without_configuration() { var settings = new NameValueCollection(); var configurationReader = new ConfigurationReader(new ConfigurationStub(settings)); var preferences = new UiPreferences(configurationReader); bool shouldBeVisible = preferences.ShouldBeVisible(CriteriaName.LastName); Assert.That(shouldBeVisible, Is.True); } [Test] public void Should_show_criterion_by_configuration() { var settings = new NameValueCollection {{"criterion.LastName.visible", "True"}}; var configurationReader = new ConfigurationReader(new ConfigurationStub(settings)); var preferences = new UiPreferences(configurationReader); bool shouldBeVisible = preferences.ShouldBeVisible(CriteriaName.LastName); Assert.That(shouldBeVisible, Is.True); } [Test] public void Should_hide_criterion_by_configuration() { var settings = new NameValueCollection {{"criterion.LastName.visible", "False"}}; var configurationReader = new ConfigurationReader(new ConfigurationStub(settings)); var preferences = new UiPreferences(configurationReader); bool shouldBeVisible = preferences.ShouldBeVisible(CriteriaName.LastName); Assert.That(shouldBeVisible, Is.False); }
Original Post: What training doesn’t teach you about reading from .Net configuration
The content of the postings is owned by the respective author. CSharpFeeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on CSharpFeeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.