Browse by Tags

All Tags » UnitTesting (RSS)

Unit Tests and Debug.Assert()

I recently found some code that had a couple of issues: There was a try/catch block that did a "catch(Exception e)".  And no, it didn't rethrow the exception.  See item #2. Inside the exception handler, it had the following code: catch (Exception e) { Debug.WriteLine(e); Debug.Assert( false ); } I thought long and hard on why anyone would do such a thing and I think I know why. Now, this is purely conjecture, but it does explain things.  This code was found inside a custom PropertyDescriptor – namely, the GetValue and SetValue methods both had this code.  I suspect that the Debug.Assert() was placed inside the catch block of these two methods so that no consumers of this component had to worry about possible data binding errors.  If there ever was a problem with data binding, the Debug.Assert(false) would throw up a dialog with a stack trace and some "Abort/Retry/Ignore" buttons, the user would click "Retry" and re-edit their data.  I don't like it, but since this component is used in a number of places in a data binding scenario, that's my theory. The problem for me is that I needed to fix some bugs in this custom PropertyDescriptor and this code had no unit tests.  So before I could consider modifying anything, I had to get the current behavior under test.  Obviously, I had to remove the Debug.Assert(), but, for legacy code, I still had to have that (ugly!) behavior. Since the Debug.Assert() is being used to report errors, I started by defining an interface that would be used for reporting errors: public interface IPropertyDescriptorValueErrorReporting { void SetValueError(Exception e); void GetValueError(Exception e); } I then moved the existing error handling code into a class I called "DefaultPropertyDescriptorValueErrorReporting": public class DefaultPropertyDescriptorValueErrorReporting : IPropertyDescriptorValueErrorReporting { #region IPropertyDescriptorValueErrorReporting Members   public void SetValueError(Exception e) { Debug.WriteLine(e); Debug.Assert( false ); }   public void GetValueError(Exception e) { Debug.WriteLine(e); Debug.Assert( false ); }   #endregion } I then added an overload on the constructor of this custom property descriptor to accept an IPropertyDescriptorValueErrorReporting public CustomPropertyDescriptor( string name, Type type, int index, IPropertyDescriptorValueErrorReporting errorReporting) : base (name, null ) For legacy code, the old constructor is modified to use the "DefaultPropertyDescriptorValueErrorReporting": public CustomPropertyDescriptor( string name, Type type, int index) : this (name, type, index, new DefaultPropertyDescriptorValueErrorReporting()) Finally, we change the exception handler to call our interface methods: catch (Exception e) { errorReporting.GetValueError(e); } And we do a call to SetValueError in the SetValue exception handler. Now I'm done!  I can proceed to create unit tests and I can pass in a mocked IPropertyDescriptorValueErrorReporting and set expectations that the GetValueError and SetValueError methods are called at the appropriate times.  Plus, I've also created an extension point so other applications can hook in to the error reporting and decide how to handle errors on a case-by-case basis. Technorati Tags: .NET , Unit Testing , Mocking

Enabling Windsor Integration in MonoRail

I recently wanted to take on old MonoRail application and update it to use Windsor for dependency injection (DI).  The application stated as a sort of prototype and slowing grew into a decent sized application.  There's a couple of places that I want to add some unit tests and I could really benefit from DI.  So I sat down to hook Windsor into the application. There's already documentation on how to integrate Windsor into MonoRail .  After all, they kind of "grew up" together.  However, the documentation is a little old and MonoRail has gone through a number of changes (some breaking) and improvements.  The " using MonoRail " site (a sort of wiki-like site) had some information on integrating Windsor into MonoRail which was more up-to-date than the Castle docs, but still left out an important section about ViewComponents.  So I thought I'd bring everything I learned into a single blog post.  I plan to take much of this and use it to update the Castle docs as well as the "using" site. Requirements You'll need to reference a few extra assemblies in your MonoRail application: Castle.DynamicProxy2.dll Castle.MicroKernel.dll Castle.Windor.dll Castle.MonoRail.WindsorExtension.dll Custom Container The first thing is to create a sub-class of the Windsor container for your MonoRail application.  This specialized version of the container will add the following capabilities: It will add a new facility which will automatically configure our Controllers for a transient lifestyle (one instance per request).  Windsor's default lifestyle is Singleton (imagine having only a single instance for each controller – yikes!!). It will automatically register all of our controllers for us.  This is optional as you can individually register each controller, but I find the automatic registration much easier. It will automatically register all of our ViewComponents .  Like controllers, this could be done individually, but this is easier. Our custom container is really quite simple.  We'll create WebAppContainer.cs in our App_Code directory.  Our constructor will call the base class constructor that will initialize the container from the config file (web.config): using Castle.Core.Resource; using Castle.Windsor.Configuration.Interpreters; using Castle.MonoRail.WindsorExtension; using Castle.Windsor; using Castle.MicroKernel.Registration; using Castle.MonoRail.Framework; using Castle.Core;   public class WebAppContainer : WindsorContainer { public WebAppContainer() : base ( new XmlInterpreter( new ConfigResource())) { }   public void Init() { } } Now let's work on our 3 items above.  We'll plug all of this into our Init() method which we'll call later when we initialize our container. First, we add a facility for MonoRail integration.  This facility is part of MonoRail: AddFacility( "rails" , new MonoRailFacility()); Next, we register all of our controllers (yes, in one statement).  My controllers are in a separate assembly so this is how my registration looks: Register( AllTypes.Of<IController>() .FromAssemblyNamed( "YourAssemblyName.Controllers" )); If your controllers are directly in your web application, you can change "FromAssemblyNamed(…)" to "FromAssembly(Assembly.GetExecutingAssembly())". Now we also need to register our ViewComponents.  This registration will also make sure that the ViewComponents are set up with a transient lifestyle: Register( AllTypes.Of<ViewComponent>() .FromAssemblyNamed( "YourAssemblyName.Controllers" ) .Configure(cr => cr.Named(cr.ServiceType.Name).LifeStyle.Is(LifestyleType.Transient)) ); That's it for the container!  Our complete, customized container looks like this: using Castle.Core.Resource; using Castle.Windsor.Configuration.Interpreters; using Castle.MonoRail.WindsorExtension; using Castle.Windsor; using Castle.MicroKernel.Registration; using Castle.MonoRail.Framework; using Castle.Core;   public class WebAppContainer : WindsorContainer { public WebAppContainer() : base ( new XmlInterpreter( new ConfigResource())) { }   public void Init() { AddFacility( "rails" , new MonoRailFacility());   Register( AllTypes.Of<IController>() .FromAssemblyNamed( "YourAssemblyName.Controllers" ));   Register( AllTypes.Of<ViewComponent>() .FromAssemblyNamed( "YourAssemblyName.Controllers" ) .Configure(cr => cr.Named(cr.ServiceType.Name).LifeStyle.Is(LifestyleType.Transient)) ); } } Integrating Our Container Now we need to hook this container into our web application.  We need to plug this into our custom HttpApplication (usually, your GlobalApplication.cs).  First, we need to add the IContainerAccessor interface: public class GlobalApplication : HttpApplication, IContainerAccessor Now add a static class variable...

ASP.NET MVC + MVC Contrib + Unit Testing

One of the key benefits of the MVC (Model View Controller) pattern is a separation of concerns that leads to better testability.  Microsoft recognizes this and will automatically create a separate MS Test project when creating a new ASP.NET MVC solution.  While this gives you a nice head start, there's room for improvement.  While actions in the MVC pattern are simply methods on a class that can easily be called by MSTest (or any unit testing framework), most web applications have interactions with supporting objects such a Request (query string, form parameters, etc…), Response (cookies, content type, headers, etc…), Session, and more.  In a live environment, these objects come as a result of the HTTP request being processed by IIS.  In a test environment, you're isolating just your controllers and actions and you don't have IIS and an entire HTTP pipeline. We can use mocking to provide "pretend" implementations of all of these objects, but there's a lot to mock.  This is where the MVC Contrib project on CodePlex can really come in handy! MVC Contrib Test Helper The MVC Contrib project gets a lot of praise for the many benefits it brings when developing for ASP.NET MVC – numerous UI helpers, Model Binders, Controller factories, etc…  But it also contains a TestHelper library that makes unit testing your controllers much easier.  By utilizing Rhino.Mocks , the MVC Contrib TestHelper can create and initialize your controller with mocked instances of: HttpRequest HttpResponse HttpSession Form HttpContext and more! In this article, I'll utilize the MVC Contrib TestHelper library to fully unit test a simple ASP.NET MVC controller.  As with many small demos, it's totally contrived, but helps illustrate the principals. Scenario We're building an ASP.NET MVC project that has to accept submissions from speakers.  We'll be doing this in a "wizard-like" fashion.  The prospective speaker will first enter their personal information (first name and last name).  The next step will have them enter their submission information.  There will be a final review point and finally, the actual submission.  Since some speakers want to submit multiple talks, we'll re-display the speakers personal information if they start the wizard up again after submitting a talk. Design In this article, we're only going to deal with the first step: collecting the speakers personal information (first name and last name).  We'll save this information in the Session object and pull it back out if the speaker returns to the beginning of the wizard after submitting a talk.  Both the speakers first name and last name are required – the user can not continue if they aren't both filled in.  The action on the controller is the "Speaker" action.  The next step in the wizard is the "SessionDetails" action. Using the information above, we have 5 test scenarios to cover: If we run the "Speaker" action with nothing in the Session: The result should be a ViewModel which has no speaker first name/last name and we should return a "View" result to ASP.NET MVC. If we run the "Speaker" action with a first name/last name in the Session: The result should be a ViewModel which as the first name/last name from the Session and should return a "View" result to ASP.NET MVC. If we run the "Speaker" action and only send in a first name: We should save the first name to the Session, but we'll also add an error for the missing last name to the ModelState and return a "Redirect" result so ASP.NET MVC will go back to the "Speaker" action and give the user the chance to enter their missing last name. Do the same test as above, but for the last name. If we run the "Speaker" action and send both a first name and a last name: The first and last name should be saved to the Session object and a "Redirect" result should be returned that tells ASP.NET MVC to go to the "SessionDetails" action. Set Up Start up a new ASP.NET MVC project and make sure you select the option to create unit tests.  The default ASP.NET MVC project comes with a Home controller.  For simplicity's sake, we'll add our actions to that controller and add our tests to the HomeControllerTests class. First, let's create a class to maintain our speaker information.  Sure, it's only two pieces of information, but this is a sample.  In the real world, we'd probably have more than this and therefore, we'll use a class: public class SpeakerInfo { public string FirstName { get; set; } public string LastName { get; set; } } Test #1 We start by writing our failing test (red), we'll throw together enough production code to get the test to pass (green), then we'll implement our actual logic and make sure...

Verifying collections/arrays in MS Unit Testing

If you're using Microsoft's unit testing framework that is built in to VS2008 (and some VS2005 SKU's), you're probably aware of the Assert class.  You use that a lot to make assertions on properties and return values to determine if your unit test passed or failed. If you try and do an assert on a collection or array (say, an array of doubles), Assert.AreEqual will always return false, even if the contents of the array match.  Example: 1: [TestMethod] 2: public void CheckArrays() 3: { 4: double [] array1 = new double [] { 2.0, 3.0, 6.7 }; 5:   6: Assert.AreEqual( new double [] { 2.0, 3.0, 6.7 }, array1); 7: } This test results in a failure: Assert.AreEqual failed. Expected:<System.Double[]>. Actual:<System.Double[]>. The reason is that with an array, the Assert class is checking for reference equality.  For something simple above you could write three different asserts – one for each element of the array.  But that is too brittle to stand the test of time (or a code review!).  Instead, Microsoft has the CollectionAssert class which will loop through the array and check each element for equality.  If we re-write the test above as: 1: [TestMethod] 2: public void CheckArrays() 3: { 4: double [] array1 = new double [] { 2.0, 3.0, 6.7 }; 5:   6: CollectionAssert.AreEqual( new double [] { 2.0, 3.0, 6.7 }, array1); 7: } We now get a passing test. Technorati Tags: UnitTesting , Collections , MSTest