Last weekend I presented a session at the third annual Chicago Code Camp entitled: Test-driven Development in .NET – Tips, Tools, and Techniques. The session was standing room only and carried into the commons area afterwards with some excellent questions from attendees. What is greater than that is that the questions didn’t stop there, they kept coming via email. One question in particular has stuck with me because it was a hurdle I myself had to overcome early on in my TDD adventures.
The question boiled down to how do you test code the depends on ASP.NET, specifically Web Configuration and Application Settings? So I thought I would put together a blog post how this can be done, and how it should be done.
To set the stage…I have a simple ASP.NET web application with one page and one class. The page load method calls the one method in the class that returns an app setting stored in the web config file.
Your first option to getting your tests to run and return the configuration and/or app settings is to tell your tests to run under the ASP.NET host process and not the VSTest host process and also tell what url to run the test under.
If you run this you will see that the test passes…eventually…after Casini is started and the test runner twiddles its thumbs for a bit. Speed is my first issue with setting up your test to run in this fashion. My second issue is that you aren’t testing the ASP.NET configuration framework so why would you need to add all this extra plumbing to make your code take that route? There is a better option!
Since we really don’t care how or where are value comes from we just need some sort of value returned so we can test our method, we can easily add a thin layer of abstraction and mock the pieces of code that depend on ASP.NET.
Lets start by creating an interface for a simple class that reads application settings.
Now we can implement the interface and add the actual code to read the app settings from the web config file.
Next we will modify our class that needs testing to use the new AppSettingsReader. Because our goal is to eventually be able to mock the settings reader we need to invert the control of the dependency and provide a mechanism for injecting the dependency. The change is fairly straightforward.
Now we have introduced a breaking change and need to modify our page and our test to accommodate the change to SomeClassThatNeedsTesting.
At this point we can run our test from above and, after we have taken a bathroom break, checked Twitter, and made a sandwich, we will notice that the test still passes. This is true because all we have done is add a layer of abstraction. We have not changed the core functionality of the process. Now that the layer of abstraction is in place we can write another test and this time instead of writing more code to please ASP.NET lets drop that dependency completely by mocking it.
To implement our mock I am going to use my mocking tool of choice, RhinoMocks. (I am purposefully not supplying a URL here because you should be using NuGet to get your packages!)
Here is our new and improved test.
If you take a look at the test you can see that the first thing that I did was create my mock AppSettingReader and set my expectations. After that I instantiated my class under test and passed in the settings reader mock.
Hope you found this useful! Complete code is available here!
Keith is a Senior Software Engineer with Falafel Software. He has been developing software since 1999 specializing in web-based solutions primarily using the Microsoft stack. He has been a Microsoft MVP in ASP.NET since 2012.
The opinions expressed herein are my own personal opinions and do not represent
my employer's view in any way.