CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Karl Seguin

.NET From Ottawa, Ontario - http://twitter.com/karlseguin/

October 2008 - Posts

  • jQuery Article and Thoughts

    I'm writting a couple articles for DotNetSlackers on jQuery. Part 1 of 2 is now available. A former colleague turned me onto jQuery a while ago, and I've been a fan ever since. It makes programming JavaScript and writting HTML fun. Aside from its slick API I think there are a couple good lessons to learn from jQuery. First, compared to other JavaScript frameworks, jQuery is extremely focused. It only does a few things but does them far better than anyone else. This makes it lightweight and a breeze to learn (seriously takes about 20 minutes) yet extremely powerful. Secondly, it solves a real problem. Everyone knows that cross-browser DOM traversal and manipulation is a serious problem. jQuery provides you a toolbox that works, rather than some pre-built furniture that simply decorates.

    There's also a good ALT.NET and Microsoft angle to jQuery. First, if you sandboxed yourself to the msdn way you wouldn't know about jQuery until a few weeks ago. You simply would have missed out on this wonderful tool. On the flip side, that Microsoft has embraced jQuery is just one of many recent moves from Microsoft which shows a concrete and sincere shift in its philosophies. Hooorraa

  • Simplicity is key to successful unit testing - Part 2

    A couple weeks ago we looked at the importance of making tests robust - which can be accomplished by keeping them simple, focused and loosely coupled. However, as you test more complicated methods, you'll find that no matter how well-written your tests are, they'll bloat and grow brittle. Let's look at a simple example:

    public ActionResult Save(int userId)
    {
       User user = repository.LoadUser(userId);
       //todo handle null user
       user.Name = Request.Form["name"];
       user.Password = Request.Form["password"];
       try
       {
          user.Update();
       }
       catch (ValidationException ve)
       {
          ViewData["Errors"] = ve;
       }
       return View();
    }
    

    Here we have a controller action responsible for handling changes made to a user. Pretty straightforward stuff, right? Unfortunately, the code isn't particularly easy to unit test (well, it isn't really difficult, but we're using a straightforward example for demonstration purposes). The problem is that our action actually has a number of distinct behaviours. One solution is to write a single monolithic test to cover everything in our method. Of course, we already know that'll make it unbelievably brittle, as well as making hard to test variations (different inputs, different return values). The other solution is to make extensive use of stubs and make sure each dependent call is accounted for.

    For example, if we want to write a test that focuses on the handling of ValidationException, we need to do quite a bit of stubbing:

    [Test]
    public void Save_SetsValidationErrorsInViewData()
    {
      var controller = Mock.PartialMock<UsersController>();
      var repository = Mock.StrictMock<IRepository>();
      var user = Mock.PartialMock<User>();
      var expected = new ValidationException("name", "invalid");
    
      Mock.SetFakeControllerContext(controller);
      repository.Stub(r => r.LoadUser(3)).Return(user);
      controller.Request.Stub(r => r.Form)
        .Repeat.Any()
        .Return(new NameValueCollection());
      user.Stub(u => u.Update()).Throw(expected);
    
      controller.Save(3);
      Assert.AreSame(expected, controller.ViewData["Errors"]);          
    }

    Even for this simple example, the test is less than ideal. We need to setup a fake controller context (using the MvcMockHelper), handle our repository interaction and our Request.Form mapping. Worse, the same setup is required for each behaviour of this method that we'll test. The solution is to break-down our method into smaller more focused chunks. Here's an extreme example:

    public ActionResult Save(int userId)
    {
       User user = BindUser(userId, Request.Form);
       UpdateUser(user);
       return View();
    }
    internal virtual User BindUser(int userId, NameValueCollection parameters)
    {
       User user = repository.LoadUser(userId);
       user.Name = parameters["name"];
       user.Password = parameters["password"];   
       return user;
    }
    internal virtual void UpdateUser(User user)
    {
       try
       {
          user.Update();
       }
       catch (ValidationException ve)
       {
          ViewData["Errors"] = ve;
       }
    }

    Now, take a look at our test:

    [Test]
    public void UpdateUser_SetsValidationErrorsInViewData()
    {
      var user = Mock.PartialMock<User>();
      var controller = new AwardsController();
      var expected = new ValidationException("name", "invalid");
    
      user.Expect(u => u.Update()).Throw(expected);
      controller.UpdateUser(user);          
      Assert.AreSame(expected, controller.ViewData["Errors"]);          
    }

    The test is majorly simplified - in fact, we don't even have to worry about our controller's context, or our interaction with the repository. The best part is that each of our methods behaviours (get the user, bind it, save it and mange the viewdata+view) can now be tested with equally simple test - rather than all-encompassing ones.

    While I realize refactoring into really small methods can pose a psychological barrier for many, it's a truly useful technique with benefits beyond testability.

More Posts

Our Sponsors

Proudly Partnered With