In a effort to maintain the testability of my code, I’ve started exposing my application settings from an abstraction layer. The settings are then passed into consumer object (classes) as needed using interface injection (aka dependency injection).
Consider the fictitious example below. The DiscountCalculator class contains the function FinalOrderAmount. This function returns total cost of an order based on the number of order items. If the number of items in the order exceeds a specific number, a discount is applied and the discounted value is returned, otherwise the original value is returned. The number of items that trigger the discount and the amount to discount the cost by, are held in an object that implements IContainDiscountSettings.
By injecting an instance of IContainDiscountSettings into the constructor, the DiscountCalculator class becomes loosely coupled to the IContainDiscountSettings instance, enabling it to be unit tested in isolation. The test below checks that the FinalOrderAmount function applies a discount when the number of items reaches equals the trigger value held in the settings object. In this instance, we’ve injected a test stub implementing IContainDiscountSettings. Using a stub in this way, allows us to set different values for each test case written.
Deriving from the ConfigurationSection
OK, so I’ve finally heeded the calls of the cool kids on twitter and started to utilise custom configuration sections in the app.config file. I don’t necessarily feel like one of the cool kids but feel I’ve got one less thing for me to get brow beaten over!
Here’s how we can an hold our DiscountSettings values in our app.config file without using the “filthy” appSettings element.
As you can see, I’ve added a section element into the configSections element to declare the config section, then added the DiscountSettings element to hold all my values as attributes. I must admit, it does make things a lot more manageable than tossing everything in the appSettings section.
We can read the values from our app using the class below…
… which derives from the ConfigurationSection class of the .NET stack and although, there is a little more ceremony than reading in from the appSettings section, there are some benefits: Decorating each required property or the class with the “IsRequired=True” property on the ConfigurationProperty attribute, ensures that an exception is thrown if the setting is missing in the config file as soon as the class is initialised, rather than than when you try to retrieve the value and use it. You can also set default values if you don’t want to specify the value in the config file but that seems a bit dirty to me.
We can declare an instance of our DiscountSettings object as so…
…and by configuring it to implement IContainDiscountSettings, an instance of it can be injected into our DiscountCalculator as needed:
Using the Interface Injection method described above, we can easily switch our application settings management solution as the need arises. By writing a class that implements the necessary settings management interface, we could easily read our settings from a database, registry or even a network stream. It also enables us to effectively test consumer object in isolation.
Any feedback would be welcome if there’s a better way of achieving this :-)