Thursday, November 05, 2009

WPF + Strong Typing

I have been working with WPF recently, and one of the things that annoys me most is the usage of strings to reference object properties. This mainly affects Bindings, but also pops up in other places such as the IDataErrorInfo interface.

Here is an example that anyone who has touched WPF should understand.

<TextBox Name="textBox1" Text="{Binding DataItem}" />

This particularly bothers me when writing a project from scratch where the data model is still evolving and there is refactoring going on. While some tools like ReSharper are pretty good at picking these up and changing them when you rename a property, you are still relying on the correct usage of a tool rather than the compiler to keep everything in sync.

Now perhaps I am just bad at bing-ing (not quite as catchy as Google’s verbs is it) but this issue seems to be really difficult to find any good coverage on. There are a number of posts around with people complaining, and there are a number of cranky comments on those blogs from people who just say deal with it, but there is very little in the way of a solution. And from what I have seen there is no attempt to improve the situation in the next release of VS/WPF/C#.

Now I don’t have a perfect solution to offer either, but I do have  a little class that makes my life easier. It is similar code to what you will find inside some LINQ providers if you dig into them and involves breaking a Lambda Expression down into a useful form (in this case a string).

First things first, this involves moving your bindings from the XAML and into the code-behind file (or some other place that has access to the controls). Personally I prefer this, I like to put as little into XAML as possible. I see the XAML as a visual layer, therefore beyond visual styling and control names I try to keep my XAML files empty. I personally do both data binding and event binding in the code behind, always have.
If this is unacceptable to you for whatever reason, then I can do nothing to help your assumed string based data binding woes.

On to the code.

   1: using System;
   2: using System.Linq.Expressions;
   3:  
   4: namespace MagicStringBlog
   5: {
   6:     public static class MagicString
   7:     {
   8:         public static string Get<T>(Expression<Func<T, object>> ex) {
   9:             string name;
  10:             switch (ex.Body.NodeType) {
  11:                 case ExpressionType.MemberAccess:
  12:                     name = ex.Body.ToString();
  13:                     break;
  14:                 case ExpressionType.Convert:
  15:                     name = ((UnaryExpression)ex.Body).Operand.ToString();
  16:                     break;
  17:                 default:
  18:                     throw new Exception(String.Format("Expression type {0} unknown", ex.Body.NodeType));
  19:             }
  20:             name = name.Substring(name.IndexOf('.') + 1);    // remove the lambda name from expression (d=>d.Test to Test)
  21:             return name;
  22:         }
  23:     }
  24: }

I stole the name MagicString from a blog post I read a while ago about configuring NHibernate and how all the strings were “magic” because you just had to assume you have typed them correctly and that they will work. (On a side note for NHibernate users, if you are using the Fluent interface you are likely to find some code very similar to the above in it somewhere)

The first thing to note is that the Func<T, object> which describes a delegate that takes a parameter of type T and returns something (of type object, so anything) is wrapped in a System.Linq.Expressions.Expression. I’ve never looked at how this precisely works, but the end result is that instead of getting a reference to a delegate that can be .Invoke()’d you get an expression tree that can be analysed, modified, compiled and then executed. Note that here I only perform step one of that sequence, there is no attempt at execution made.
These expressions are at the core of how a LINQ provider such as LINQ-to-SQL can take your .Where(d=>d.PK==1) and turn it into a SQL statement rather than returning all the objects from the database and running that piece of code over them as CLR objects.

The contents of the method are not as important as the signature, but basically it analyses the expression, pulls out the name of the property being referenced and returns it. The only complication comes from types that are wrapped to be returned as an object, for example bool, then you need to dig inside the casting operator.

And here is how we call it in the case of a data binding.

textBox2.SetBinding(TextBox.TextProperty, MagicString.Get<DataClass>(x => x.DataItem));

For the record here is the data class that is being used. Complicated!

   1: namespace MagicStringBlog
   2: {
   3:     public class DataClass
   4:     {
   5:         public int DataItem { get; set; }
   6:     }
   7: }

It’s worth noting that I find the binding expression above too long as well, and have created an Extension Method on controls that has the following signature.

public static void Bind<T>(this FrameworkElement el, DependencyProperty dp, Expression<Func<T, object>> ex)

Which cuts down the call time binding code to

textBox2.Bind<DataClass>(TextBox.TextProperty, d=>d.DataItem);

With this in place, even the Visual Studio rename tools will find the property and tidy up its name if your objects change, and it will be checked at compile time.

Now I said earlier that this solution is not perfect, and I meant that. One problem is that all we are doing is turning a string literal into a runtime generated string. There is nothing that is going to check that the DataContext of the TextBox is actually of the type you are binding to, and you are going to suffer some performance hit (I haven’t run the numbers to see how much of one), but the safety this does bring I find useful. I didn’t move to C# only to need to search my code for string literals every time I want to rename a property.

Here is a project that includes the code and shows both regular binding and “MagicString” binding.

Labels: , ,

Tuesday, February 03, 2009

Moq: Mocking GetEnumerator()

In my last post I made mention that it was easier not to use the Enumerators on HTTP context objects when you want to unit test with mocking. This is due to some annoyances with casting (as they predate generics) that can be avoided with simple for() loops instead of foreach().

Today however, I am going to look at mocking GetEnumerator() in a more general sense should you ever need it. Also for the first time I am going to pop the code onto SkyDrive and include line numbers in my code snippets.

We start with a simple "business object" that iterates over a set of products returning a list of their names. Nice useless test code as always.

   1: public class BizProducts
   2: {
   3:     private IProductsRepository db;
   4:  
   5:     public BizProducts(IProductsRepository repository) {
   6:         db = repository;
   7:     }
   8:  
   9:     public string List() {
  10:         StringBuilder sb = new StringBuilder();
  11:         foreach (Product p in db) {
  12:             sb.AppendLine(p.ProductName);
  13:         }
  14:         return sb.ToString();
  15:     }
  16: }

The business object expects to be passed its data store rather than creating the instance itself. This has two benefits, it becomes far easier to unit test as we can pass in a mocked set of data rather than the concrete class used in the real code, and we can also plug it into a dependency injection framework easily.

The product repository interface and the underlying product class look like this. Note that the IProductsRepository implements the IEnumerable<Product> interface, which exposes a strongly typed GetEnumerator() method rather than the older object one. This comes from System.Collections.Generic

   1: public interface IProductsRepository : IEnumerable<Product>
   2: {
   3: }
   4:  
   5: public class Product
   6: {
   7:     public int ProductID { get; set; }
   8:     public string ProductName { get; set; }
   9: }

Now a concrete implementation of the IProductsRepository is likely to connect to SQL Server for its data, but this can be a pain with unit testing as it requires every developer who is sharing tests to have consistent data that can be coded into the unit tests. It also means a test for the business object needs to rely on a bug free data layer to succeed. It is better to test one thing at a time, leave testing the data layer to the data layer tests. This means we need to mock the data layer in business object tests, which means we need to sort out mocking the implicit GetEnumerator() called by the foreach() loop.

Here is a unit test you can use that will mock the IProductsRepository interface using Moq

   1: [TestClass]
   2: public class BizProductsTests
   3: {
   4:     [TestMethod]
   5:     public void TestList() {
   6:         Mock<IProductsRepository> repository = new Mock<IProductsRepository>();
   7:         repository.Expect(d => d.GetEnumerator()).Returns(ProductList());
   8:         BizProducts biz = new BizProducts(repository.Object);
   9:  
  10:         string s = biz.List();
  11:         Assert.AreEqual("First Product\r\nSecond Product\r\n", s);
  12:     }
  13:  
  14:     public IEnumerator<Product> ProductList() {
  15:         yield return new Product() { ProductID = 1, ProductName = "First Product" };
  16:         yield return new Product() { ProductID = 2, ProductName = "Second Product" };
  17:     }
  18: }

Line 7 sets up the expectation that the GetEnumerator() method should return the IEnumerator<Product> returned by the ProductList() method. It turns out one of the easiest ways to get your hands on an enumerator is with the lovely yield statement. Better yet since it comes out of a method, you could set this list of products up once and use it through all appropriate unit tests.
Another option not shown here is by using a generic collection such as List<Product> to store your products, and then return its GetEnumerator(), make sure you use a collection from System.Collections.Generic though, older collections will not implement the generic IEnumerable<> interface.
I prefer the yield method as it is simpler to set up and keeps the actual unit test code shorter, but if you need to inspect the underlying objects afterwards or prefer to keep the code all in one place than the List<> option would be the way to go.

Here is the link to the hopefully working solution file on SkyDrive.

Labels: , , ,

Thursday, January 29, 2009

ASP.NET MVC: Unit Test File Upload with Moq

Microsoft released the ASP.NET MVC Release Candidate yesterday (Link). One thing that pricked my ears in the release notes was a change to the ControllerContext that would apparently make it easier to use a mocking tool to unit test actions that needed to interact with the standard HTTP objects.

I gave up on mocking back at Preview 3 of the MVC framework, and instead I was slowly building up a library of classes using the Http...Base (eg HttpRequestBase) classes that implemented each feature as needed. It was a little bit of work, but at least it did work.

With ScottGu's example in hand and a copy of Moq installed and referenced in my test project I set about replacing my own classes with the appropriate mocks in each test of a project I am working on at the moment. The results were surprisingly good, I am now able to mock every part of the web context I am currently using with ease.

One scenario I was pretty impressed with that I will share with you is mocking the Request.Files collection to test uploading files to a site. I will start with a simple Upload method and build a few iterations of the unit test to show what is going on. This isn't a lesson on mocking or unit tests, I have assumed you have some knowledge of both. I am simply showing off a particular mock I was impressed with.

First we need a new ASP.MVC project, we will add an Upload action to the Home controller like so.

public ActionResult Upload() {
    string s = "Uploaded " + Request.Files.Count.ToString() + " files.<br/>\n";
    for (int i = 0; i < Request.Files.Count; i++) {
        using (StreamReader reader = new StreamReader(Request.Files[i].InputStream)) {
            s += String.Format("File {0}: {1}<br/>\n", Request.Files[i].FileName, reader.ReadToEnd());
        }
    }
    return Content(s);
}

Obviously not a method you would use, but suits our purposes for demonstration. It simply loops through the files collection and writes out the name and contents of each file in the response. Note: It is easier to test this code with the for() loop instead of a foreach() as you do not need to mock GetEnumerator() which can be clumsy and in this case was struggling with casting.

If we put together a simple unit test for this, you will soon see the problem.

[TestMethod]
public void TestUpload() {
    HomeController c = new HomeController();
    ActionResult r = c.Upload();
    Assert.IsInstanceOfType(r, typeof(ContentResult));
    Assert.AreNotEqual("", ((ContentResult)r).Content);                        
}

This test throws a null exception on the first line of the Upload method because it can not access Request. On top of this problem it is not immediately obvious in your unit test how you even "upload" a file to the action. Because your unit test is not a web request, all the architecture of a usual web call (I am calling it the context through this post) is not created. The whole point of using mocking here is to recreate the part of the context the test needs to be able to succeed. Lets fix one step at a time though.

Since we are currently failing on Request.Files.Count, this will be the first mock we add. It looks like this.

[TestMethod]
public void TestUpload() {
    HomeController c = new HomeController();
    Mock<ControllerContext> cc = new Mock<ControllerContext>();
    cc.Expect(d => d.HttpContext.Request.Files.Count).Returns(2);
    c.ControllerContext = cc.Object;
    
    ActionResult r = c.Upload();
    Assert.IsInstanceOfType(r, typeof(ContentResult));
    Assert.AreNotEqual("", ((ContentResult)r).Content);                        
}

The object we want to mock is the ControllerContext, it can be attached to the Controller and contains all the HTTP classes we need to manipulate to fake a web request.
The syntax of Moq is very concise and provided you know how to read a lambda you will note that I am telling the mock that I expect HttpContext.Request.Files.Count to return 2.
The other key part of the Moq syntax is that to get the actual instance of the mocked object you access the .Object property. So we assign this to the controller as the context it should use.
If we run this test it still fails, but now it is failing on the first usage of the file inside the for loop. The code now thinks there are two files uploaded, it just couldn't find them when it went looking. If you have never played with mocking before, this simple concept of "I expect xxx to return yyy" will get you a long way improving your unit tests against an MVC website. It is fairly straight forward to mock any part of web context (Request, Response, Server, etc) just like this. But back to file uploads.

So what we need to do now, is to add two new expectations to the mocked ControllerContext to state that HttpContext.Request.Files[0] should return our first file and that .Files[1] should return our second file. This however begs the question, what exactly do they return. Our code is expecting objects of type HttpPostedFile to be returned from the Files collection, helpfully ASP.NET MVC has included an HttpPostedFileBase class that can be mocked to represent the objects of the Request.Files collection. So we simply need to create two of these, mocking the FileName and InputStream properties we have used in our code to return the relevant details from our test files. Then tell the mocked ControllerContext to return them. Putting this all together looks like this. Note that I am returning .Object again, it is important to understand the difference between the mocking configuration object and the actual instance you should use in your code.

[TestMethod]
public void TestUpload() {
    HomeController c = new HomeController();
    Mock<ControllerContext> cc = new Mock<ControllerContext>();
    UTF8Encoding enc = new UTF8Encoding();

    Mock<HttpPostedFileBase> file1 = new Mock<HttpPostedFileBase>();
    file1.Expect(d => d.FileName).Returns("test1.txt");
    file1.Expect(d => d.InputStream).Returns(new MemoryStream(enc.GetBytes(Resources.UploadTestFiles.test1)));

    Mock<HttpPostedFileBase> file2 = new Mock<HttpPostedFileBase>();
    file2.Expect(d => d.FileName).Returns("test2.txt");
    file2.Expect(d => d.InputStream).Returns(new MemoryStream(enc.GetBytes(Resources.UploadTestFiles.test2)));
                
    cc.Expect(d => d.HttpContext.Request.Files.Count).Returns(2);
    cc.Expect(d => d.HttpContext.Request.Files[0]).Returns(file1.Object);
    cc.Expect(d => d.HttpContext.Request.Files[1]).Returns(file2.Object);
    c.ControllerContext = cc.Object;

    ActionResult r = c.Upload();
    Assert.IsInstanceOfType(r, typeof(ContentResult));
    Assert.AreNotEqual("Uploaded 2 files.<br/>\nFile test1.txt: Contents of test file 1<br/>\nFile test2.txt: Contents of test file 2<br/>", ((ContentResult)r).Content);
This test now passes and we can be confident that our action for handling the upload of files is working correctly.

 Note: To host the actual test files I am uploading I have created a Resource file called UploadTestFiles and added two .txt files to it that are stored under the Resources sub-directory of the unit test project. I have found this to be a useful way to keep control of my test files. Using binary files is even easier than text files as you get direct access as a Stream, this saves you the encoding code you see above to turn the string into the Stream needed by the HttpPostedFile class.

So there you have it! Mocking of ASP.NET MVC has come a long way since I last looked at it. Exactly which release each piece of the puzzle dropped in, I can't say, but where we are at now with the Release Candidate is working quite well for me so far.

If you have had troubles with mocking the web context in ASP.NET MVC previously or simply avoided unit tests for actions that needed it. Now is a good time to take another look.

Labels: , , , , ,

Wednesday, May 07, 2008

The 'yield' Keyword

I have recently been brushing up on my Computer Science training, implementing various data structures and algorithms, O(log n) searching, that sort of thing. While traversing a binary tree returning it's contents in sorted order, I really wanted to put the yield keyword to use.

The yield keyword was introduced in .NET 2.0 and is used when added iteration features to a class. Typically this means when implementing the IEnumerable or IEnumerable<T> interfaces.

One of the most striking examples I have seen that demonstrates how it works is a simple method that returns an iterator over the numbers 1 to 10.

public IEnumerator<int> GetEnumerator() {
    yield return 1;
    yield return 2;
    yield return 3;
    yield return 4;
    yield return 5;
    yield return 6;
    yield return 7;
    yield return 8;
    yield return 9;
    yield return 10;
}

I think this simple-as-they-come example really represents what is going on here. The compiler uses this method to put together an iterator. When the first MoveNext() is called, the method executes until the first yield is reached. The value is returned and the state is saved, when the next MoveNext() is called, the code keeps running from where it was until the next yield is reached.
The iterator reaches its end when the function has no more statements to execute, or a yield break; is called.

I've long liked this concept, but rarely had any use for it that wasn't nearly as trivial as the example above. The big reason is that most of our data structures are already written for us these days. Need a list? Grab it from System.Collections. Therefore I rarely need to iterate in anything but a linear fashion.

So it wasn't until my recent adventures into re-learning some Computer Science theory that I was presented with a good chance to put this to work.
As I was saying, I was using a binary tree to store and sort a set of int's and then needed to pull them back out again in order. For any given node of the tree, this means returning the Left branch followed by the node's own value followed by the Right branch. By implementing the IEnumerable<int> interface on my Node class I was exposing the capability to use foreach(int i in Node) {} to return the values. All I needed was the code for the iterator.

public IEnumerator<int> GetEnumerator() {
    if (Left != null) {
        foreach (int i in Left) {
            yield return i;
        }
    }
    yield return Value;
    if (Right != null) {
        foreach (int i in Right) {
            yield return i;
        }
    }
}

Now I am not going to declare this is a perfect implementation to traverse a Binary Tree. I am not certain exactly what code this compiles down to, but assuming it becomes recursive makes it less than ideal.
Putting that aside for the moment however, I was really impressed with how succinctly this let me express how I wanted the code to behave.

All you could ask for on top of this at a language level is something like a
yield iterate Left;
Now that would really cut the code down.

Labels: ,

Tuesday, April 15, 2008

LINQ-to-SQL: Generic Primary Key function

An issue I have seen blogged about a number of times with LINQ-to-SQL is that by strong typing queries, you lose the ability to create generic functions for processes such as fetching records by their Primary Key. A recent example is Rick Strahl who offers a number of good options for getting around this, while not being particularly happy with any of them. In the comments of Rick's post Richard Deeming offers a solution very similar to my own, which is to use the Meta-data provided by LINQ-to-SQL and the functionality of System.Linq.Expressions to create a simple and robust solution.

Here is an extension method you can pop onto your DataContext object to facilitate the pulling of records from the database by their Primary Key.

public static class DataContextHelpers
{
    public static T GetByPk<T>(this DataContext context, object pk) where T : class {
        var table = context.GetTable<T>();
        var mapping = context.Mapping.GetTable(typeof(T));
        var pkfield = mapping.RowType.DataMembers.SingleOrDefault(d => d.IsPrimaryKey);
        if (pkfield == null)
            throw new Exception(String.Format("Table {0} does not contain a Primary Key field", mapping.TableName));
        var param = Expression.Parameter(typeof(T), "e");
        var predicate = Expression.Lambda<Func<T, bool>>(Expression.Equal(Expression.Property(param, pkfield.Name), Expression.Constant(pk)), param);
        return table.SingleOrDefault(predicate);
    }
}

You can then run this code by doing the following

MyDataContext db = new MyDataContext();
Product p = db.GetByPk<Product>(1);

Note: Excuse the excessive use of "var". However it can be useful in the context of a code-snippet as it removes the need for you to work out all the using statements needed to make the code work.

So what does this code do, first we get a reference to the LINQ-to-SQL meta data store for the table we are querying, then pull out the Primary Key field for the table. It then builds a lambda expression tree that compares the Primary Key field of the parameter (that will be passed to the expression later) against the constant id passed to the function. This expression is then passed into LINQ-to-SQL where it can be decomposed and turned into SQL code. This is effectively the same as writing the lambda  "e=>e.PK == id", except that we work out the name for PK at run-time.

I have attached this as an extension method on the DataContext, but if you are using a base class for your entities, or writing a generic business object, you should be able to manipulate this fairly easily to do as you wish.
I have only scratched the surface of what may be possible with this technique of building code through Expression Tress, there is bound to be some interesting work done in this area as people get more and more accustomed to the concept.

Labels: , ,

Friday, March 28, 2008

ASP.NET MVC Application Layout

I am slowly evolving my general layout for ASP.NET MVC applications as I come more and more to grips with the framework and they ways I am most comfortable using it.

This post is going to be a bit of an overview of how I am laying out my project at the moment in case it is of use to anyone.

Controllers

I have reduced the work-load of my controllers substantially since my early attempts. My average controller action now performs three simple steps. Create a Model, Pass the relevant state data from the URL to the Model, Choose and render a View.
When combined with the new ActionFilters to handle things like Authentication and SSL, I can really see my controllers being replaced by some form of Inversion-of-Control class that is configured up and simply runs the same piece of code for every action using the configuration as a guide.

Models

As my controllers have become simpler, my models have become more complicated. I am still using LINQ-to-SQL to connect to the database, but there is a bit more to models than just this.
My models have two sets of properties, those that are get/set which provide an interface for the controller to tell the model what state the user has requested (ie ProductID = 1) and those that are only get. The later provide the interface the View should use to present it's data. Often I don't load each piece of this data unless it is requested.

Views

I have killed off code behind files. I still think strong typing views is a good idea though.
Rather than having a code behind file on every page just to set up this strong typing, I am using a single Views.cs file for each directory of Views, it contains empty definitions for each page eg
public partial class Home : ViewPage<HomeModel> { }
The main benefit here is that it removes clutter, both in terms of files in the project and cuts down the @Page declaration in the .aspx files
For the project at hand this is very useful as I will need to deal with designers who will be making lots of pages based around a small number of models. So I will have a basic set of page models and you simply point that page at the one that provides the appropriate data set.

Testing

Testing of Controllers and Models is a fairly straight forward task now as they both have well defined roles. Testing a controller involves checking the correct View has been chosen and the a model has been correctly chosen and sent to the View. Testing a model involves setting different state configurations and then checking to see the data public data to be used by the view is correctly set.
Views are still causing head-aches for testing though. Getting a view to render down to a string from the context of a Unit Test is proving difficult. I should get my hands on a spare box to set up as a Continuous Integration and Test box soon though and if nothing else I will be able to use one of the UAT web tools to test Views along with the whole process flow and performance of the app.
I am also finding that using subclasses of the new Http*Base classes is an easier proposition than Mocking these classes. I have completely removed Mocking from my tests for the moment, though I learnt a lot from the excursion and will definitely find a use for the technique in the future.

Drawbacks

The only real concern I have at the moment is exposing LINQ-to-SQL classes through the model for the view to consume. This is effectively tightly coupling my views to the LINQ-to-SQL back-end. I believe to be a "truer" MVC application the data source should be easier to replace. If I wanted to switch to a disconnected web service based data source (for an extreme example) I would currently need to create a set of data classes that matched the LINQ-to-SQL classes, a massive task. It's near impossible to resist the lure of LINQ-to-SQL though, it is just so nice to work with.
I am hoping that the forth coming LINQ-to-Entities will reduce my concerns by at least offering a path to a different database on the back-end even if I can still not move to a totally different type of data source.

Conclusion

The more I use the framework, the more I like it. The recent release of the source code for the framework is a nice bonus, it has made debugging a few things easier and will make extending the framework much easier.

Labels: , ,

Wednesday, March 12, 2008

RenderComponent() or RenderUserControl()

One thing I have always needed to do in my web sites is break sections of pages out into a re-usable component.
If you look at http://www.ht.com.au the "Featured Product Of The Month" panel displays three product "patches". This exact same patch is used on the Cart page and the Hub pages. It is a nice little class/template that you pass a product number to and it spits back the HTML for that patch, which you write out like any other expression in your template.

When I first went looking for this functionality in ASP.NET MVC all I could find was the RenderUserControl() method on the Html Helper class. Called like this
<%= Html.RenderUserControl("path_to_ascx_file") %>

What instantly bothered me about this call was that it heads straight off to a "View" if I wanted to supply any logic, say to turn my product number into an actual product object, then go look up some other information about it, all this code would need to go into the View, or at least into the Code Behind page of the View, which is just as bad. It wasn't very MVC to me.

In the March Preview 2 release of the MVC Framework however they added a new ComponentController base class and a RenderComponent() method to the Html Helper class. Now you can call
<%= Html.RenderComponent<PatchController>(c=>c.ProductPatch(1)) %>
This will call the ProductPatch() method on the PatchController class and pass in the parameter of 1. Now you have a MVC pattern, from within the controller you configure up your model, pick a view to render and fire it all off. The result is the output of the view gets stuck on a RenderedHtml property of the controller that the Html Helper picks up and inserts back into the parent page. My dreams had come true!

Sadly when I went to implement this, a bug popped its head up. If you attempt to pass a variable into the lambda rather than a constant (so ViewData.ProductID instead of 1) there is a Cast Exception thrown where the expression can not be cast from a variable expression to a constant expression.
This bug was reported today on the MVC forums, and as such had prompted me to respond there and put together this post, something I had been intending to do for a few days now since I spotted it.

I have a work around that is probably a bit hacky but has allowed me to continue on working until the team works out a way around the bug. If you create a subclass of ViewPage from which you subclass all your actual ViewPages, then you can pop this method in that subclass, alternatively set up an Extension Method for the ViewPage class to save you the trouble.

This code assumes all your components live in a single Controller (a side effect of which is a cleaner calling syntax), if this is not the case, then you can easily refactor the type of the controller out of the method and pass it in like the HtmlHelper method does.

public string RenderComponent(Expression<Action<PatchController>> action)
{
    var controller = new PatchController();
    controller.Context = this.ViewContext;
    var ex = action.Compile();
    ex.Invoke(controller);
    return controller.RenderedHtml;
}

This allows calling a component like this
<%= RenderComponent(c => c.ProductPath(ViewData.ProductID)) %>
and will work with both variables and constants. Shorter and better!

When I have gone looking for prior references to this method on the web, I always seem to run into religious wars about whether Components/UserControls/Partials or various other names for a similar concept have any place in MVC or web sites in general, with most people seeming to think they do not. I personally don't see how people can live without them. Hopefully this side of the framework does not get overlooked in the future, or worse, dropped.

Labels: , , ,

ASP.NET MVC - Testing

I have been further exploring the concepts of Test Driven Development of late, in particular around the ASP.NET MVC framework.

One concept that is very new to me is mocking. I have been using Rhino Mocks. This is not going to be a post about mocking, I am far much of a novice to offer any useful advice on this front just yet. However, it is pretty cool stuff and worth a read.

The MVC team have been talking a lot about testing and mocking lately, and I have found that trying to get a clear picture of exactly where they are at is quite difficult. Most examples and blogs pre-date the latest code refresh and either do or do-not work because of this. One useful resource so far though is this post from Scott Hanselman.

He provides a nice simple set of Mocks for the basic HTTPContext objects, which at this stage are very useful if you want to unit test your controllers.

It is not a complete solution though. The real sticking point is the RedirectToAction() method. It is difficult to mock. Over on MvcContrib however they have an implementation that uses interception classes from the Castle project to intercept calls to RedirectToAction() to supply their own functionality. A clever if cumbersome approach.

The following code snippets have a few dependencies. The Rhino Mocks dlls can be found at the URL I mentioned above, and the Castle.Core and Castle.DynamicProxy2 dlls can be found amongst the MvcContrib release.

Now on to some code. I have a method in my controller unit test base class to create a controller for me, configure up the mocked HTTPContext objects from scott, add a fake ViewEngine and intercept the RedirectToAction() method. Works well so far, and looks a bit like this.

public T CreateController<T>() where T : Controller, new()
{
    ProxyGenerator generator = new ProxyGenerator();
    T c = (T)generator.CreateClassProxy(typeof(T), new ControllerInterceptor(this));
    c.ViewEngine = new MockViewEngine();
    Mocks.SetFakeControllerContext(c);
    return c;
}

ProxyGenerator comes from Castle.
Mocks is a MockRepository stored on the base class.
MockViewEngine is an empty class that implements IViewEngine but does nothing yet, I want to implement something on this but I have not decided exactly what yet.

The interceptor looks like this. I had to change the one from MvcContrib because it was not working on the new Preview 2 release of MVC. Also I still wanted it to let the ViewEngine get involved incase I wanted processing there, something the MvcContrib did not do.

public class ControllerInterceptor : IInterceptor
{
    private TestClassController _parent;

    public ControllerInterceptor(TestClassController parent)
    {
        _parent = parent;
    }

    public void Intercept(IInvocation invocation)
    {
        if (invocation.Method.Name == "RenderView" && invocation.Arguments.Length == 3)
        {
            string viewName = (string)invocation.Arguments[0];
            string masterName = (string)invocation.Arguments[1];
            object viewData = (object)invocation.Arguments[2];
            _parent.RenderViewData = new RenderViewData
            {
                ViewName = viewName,
                MasterName = masterName,
                ViewData = viewData
            };
            //return;
        }
        if (invocation.Method.Name == "RedirectToAction" && invocation.Arguments.Length == 1)
        {
            RouteValueDictionary value = invocation.Arguments[0] as RouteValueDictionary;
            string actionName = value.ContainsKey("Action") ? (string)value["Action"] : "";
            string controllerName = value.ContainsKey("Controller") ? (string)value["Controller"] : "";
            _parent.RedirectToActionData = new RedirectToActionData
            {
                ActionName = actionName,
                ControllerName = controllerName
            };
            return;
        }
        invocation.Proceed();
    }
}

With all this set up and hooked together (I have left a few bits out, you will need to create the RenderViewData and RedirectToActionData classes, just holders for the properties used) you can reduce your actual unit testing code down pretty small.

[TestMethod()]
public void IndexTest()
{
    var controller = CreateController<HomeController>();
    controller.Index();
    Assert.AreEqual("Index", RenderViewData.ViewName);
}


[TestMethod()]
public void ListNotFoundTest()
{
    var controller = CreateController<ProductController>();
    controller.List("1000", 1);
    Assert.AreEqual("ProductNotFound", RedirectToActionData.ActionName);
}

Its a shame that such simple tests currently require such elaborate mechanisms. The MVC guys assure us that they are listening and will be bundling in helpers or changing the framework to make these things simpler in the coming releases, for the time being though it is a bit of fun if you give it a chance.

One thing I would like to do is integrate Route testing with Controller testing. So instead of calling
Controller.List("1000", 1);
I could
CallURL("/Product/List/1000/1");
and have the routing classes fire up and map the URL through.

I would also later like a simple way to compile the .aspx view. I dont really need to run it as I don't want to check its output at this stage. But simply checking it compiled would be a good start. This is why I have a placeholder ViewEngine at the moment instead of just mocking RenderView() to do nothing.

Overall I am very happy with the framework, I am waiting to get my hands on a dedicated test server in the near future to set up  Continuous Integration and some load/performance tests. That should be fun.

Labels: , , ,