You know an advert is intensely annoying when you start whistling the tune from it even though you hate it. #gocompare 3 days ago
14
Jun

Productivity suggestion: put your unit tests in the same project as your production code

I’ve been doing a bit of work with Django again over the weekend. One of the things I like about Django is that you put your unit tests in the same directory as your models and views in a file called tests.py. Because this sits just next to your production code, it makes writing unit tests a very natural and easy way of working.

This is in complete contrast to the way things are done in .NET, where most developers put their unit tests in a separate project, preferring instead to provide a separation of concerns and keep the size of their build output down.

The problem with that is it’s a complete faff. Because your unit tests end up in a totally different part of your solution to the code they are testing, you have to navigate all over the place through the solution explorer to get between two files that you should really be working with together all the time. It’s like trying to cook a meal when your fridge freezer is in the garage, the oven is in the attic, and the kitchen sink is in the basement.

I personally find this makes me write fewer unit tests than I otherwise would. That is bad.

The other problem is that it’s much more difficult to unit test your assembly’s internal classes. You can of course use the [InternalsVisibleTo] attribute to expose them to your test assembly though, but even so it’s a little bit awkward. Additionally, since you have an extra project in your solution, it takes longer to load into Visual Studio, and longer to build. On a large solution with a lot of projects, it can get very sluggish indeed.

The argument against putting test code in the same assembly as production code is of course that you don’t want to bloat your release build. However, it’s perfectly possible to get round this by wrapping your test classes in conditional (#if) compiler directives. It is even possible — in fact, it’s surprisingly easy — to knock out the references to test framework assemblies such as Gallio, MbUnit, Moq, and so on from release builds. You can’t do it directly from the Visual Studio IDE, but if you open up your .csproj file itself in a text editor you can add a Condition attribute to the references you want to omit. For example, this code would omit the MbUnit assembly from your Release configuration, while including it in your Debug configuration (and any other configurations you may have):

<Reference
    Include="MbUnit, Version=3.1.0.0,
        Culture=neutral, PublicKeyToken=eb9cfa67ee6ab36e,
        processorArchitecture=MSIL"
    Condition="'$(Configuration)' != 'Release'" />

What do you think, readers? Are there any other good reasons why you shouldn’t do this? Personally, I can’t think of any.

29
Sep

Book review: The Art of Unit Testing

Unit testing is one of the programming disciplines that, to my mind at least, sets apart the reputable developers from the cowboys. Test driven development has become increasingly popular over the past few years, and for many teams, it’s becoming as fundamental a discipline as using source control. It’s an idea that sounds almost like a no-brainer at first: you write a bunch of methods that feed test data into your code and examine the result, and they report either success or failure. Then when you start extending and modifying your code, you can re-run your tests to check that everything still works as it’s supposed to, and you haven’t broken any dependencies.

Yet of all the programming disciplines that I’ve had to get to grips with over the years, unit testing has probably been one of the most difficult. Setting up your project to facilitate automated testing involves quite a lot of groundwork. You have to configure a test environment, perhaps with a test database or other form of test data source, and you also have to completely re-think the way you write your code. It requires greater discipline — it’s all too easy to think “Stuff that,” and slip into the old mindset of just slapping down your code and testing it manually. Some legacy code may seem almost impossible to test, especially if it is a Big Ball of Mud with long, multi-purpose methods and no clear separation of concerns. Then there is the question of what to do with external dependencies — components that are beyond the control of your unit tests, such as third party web services, input devices, and even the current date and time.

The Art of Unit TestingIf you’re wrestling with problems such as these, Roy Osherove’s book, The Art of Unit Testing, is a must-read. Most treatments of unit testing that I’ve come across only cover the topic at a fairly basic level, but this one picks up where they leave off. I was pleased to see some good solid chapters on stubs, mocks and dependency injection, for instance: these are essential tools needed to break external dependencies. I was also pleased to see a whole chapter devoted to working effectively with legacy code; another whole chapter is devoted to the political and organisational implications of introducing unit testing into your organisation.

The book assumes a basic familiarity with object oriented programming and design patterns (which every working developer should understand properly anyway) but it isn’t a difficult read, and it explains things very clearly. Code samples are given in C#, but developers working with other languages will also find much in it of benefit. There are plenty of suggestions that may not have occurred to you, and you’ll end up much more aware of the “tricks of the trade.”

My only disappointment was that four major, and potentially thorny, aspects of the subject — database, UI, web and thread-related testing — were only given a brief overview in the second half of Appendix B. Of course it could be argued that these were outside the scope of this book — indeed, Osherove argues that unit testing in some of these areas in particular have a relatively low return on investment — and in others, unit testing frameworks and methodologies are still very much in their infancy. However, I was hoping for a somewhat more extensive treatment of these aspects of the subject and it was a little bit disappointing that they only got six pages.

But this doesn’t detract from the value of the book. Whether unit testing is your “thing” or not, it is very much a must-read for every working .NET developer, and indeed for developers working with other languages too. It deserves to be as much a classic as books such as Code Complete, Design Patterns, or Martin Fowler’s Refactoring.

04
May

Handling exceptions in assembly-level setup methods in MbUnit

MbUnit allows you to run assembly-level setup and teardown methods as part of your unit tests using the AssemblyCleanUpAttribute:

[assembly: AssemblyCleanUp(typeof(AssemblyCleaner))]
public class AssemblyCleaner
{
    [SetUp]
    public static void SetUp()
    {
        // blah
    }
    [TearDown]
    public static void TearDown()
    {
        // blah
    }
}

This is very useful if you want to do something like restore your database to a known configuration, perhaps incorporating all your change scripts into your unit tests. Unfortunately, there is a little gotcha. If your SetUp() method throws an exception, none of your unit tests will run, but MbUnit will still report success.

For what it’s worth, I think this is a bug, not a feature, but there is a way round it. Capture any exception, and create a unit test that re-throws it:

[assembly: AssemblyCleanUp(typeof(AssemblyCleaner))]

public class AssemblyCleaner
{
    private static Exception setupException = null;

    [SetUp]
    public static void SetUp()
    {
        try {
            // blah
        }
        catch (Exception ex) {
            setupException = ex;
        }
    }

    [TearDown]
    public static void TearDown()
    {
        // blah
    }

    internal static void RethrowSetupException()
    {
        if (setupException != null) {
            // Wrap the original exception to preserve its stack trace
            throw new InvalidOperationException(
                "An error occurred when setting up the tests",
                setupException);
        }
    }
}

// You need to have your unit tests in a separate class.
// MbUnit doesn't like you including test fixtures
// in your assembly cleanup class.

[TestFixture]
public class AssemblyCleanerTest
{
    [Test]
    public void ReportSetupException()
    {
        AssemblyCleaner.RethrowSetupException()
    }
}
27
Oct

Unit testing URL generation and Html.ActionLink in ASP.NET MVC

As I’ve been working with ASP.NET MVC lately on a couple of websites, the one thing I’ve found the hardest to get used to is the routing engine. Getting it set up to parse your URL to give you a route is straightforward enough — the hard, and often confusing, part is the helper functions such as Html.ActionLink that generate URLs from route data. Sometimes the URLs look different to what you expect, but they work nonetheless; at other times, they are just plain wrong, especially if you have a complex routing table set up.

The logic behind constructing the URLs is fairly complex, and depends not only on the route data that you pass into the ActionLink method, but also on the route data that comes from the original URL that you used to access the page in the first place. If you have routes that are any more complex than the fairly trivial examples that come in the out of the box application templates, it can quickly get pretty confusing. Furthermore, chopping and changing the order in which you register your routes can get things totally out of kilter, so you really need a comprehensive suite of unit tests to be able to tackle it with any hope of retaining your sanity whatsoever.

The subject of unit testing your routes to make sure that you are getting the correct route data out of them has been covered by Phil Haack and Stephen Walther, so I won’t go into any further detail about that aspect here. However, I’m going to expand a bit on Phil’s methods to show how to test things the other way round: making sure that when you pass some route data in to Html.ActionLink, it gives you the URL that you expect.

As with Phil’s sample code, I’ve used Moq to mock the context, request and response, and I’m using Eilon Lipton’s technique of using an anonymous class as a dictionary literal. You can download the code as a Visual Studio solution if you want to get up and running with it straight away. Here’s a quick look at the methods that do all the work:

string FindUrlToRoute(string currentPage, object routeData)
{
	var mockContext = new Mock<HttpContextBase>();
	var mockRequest = new Mock<HttpRequestBase>();
	var mockResponse = new Mock<HttpResponseBase>();

	mockContext.Expect(c => c.Request).Returns(mockRequest.Object);
	mockContext.Expect(c => c.Response).Returns(mockResponse.Object);
	mockRequest.Expect(c => c.AppRelativeCurrentExecutionFilePath)
		.Returns(currentPage);
	mockResponse
		.Expect(c => c.ApplyAppPathModifier(It.IsAny<string>()))
		.Returns((string s) => s);

	var route = routes.GetRouteData(mockContext.Object);

	var requestContext 
		= new RequestContext(mockContext.Object, route);
	var url = new UrlHelper(requestContext);
	var dict = new RouteValueDictionary();

	foreach (PropertyValue property in GetProperties(routeData)) {
		dict[property.Name] = property.Value;
	}

	var path = routes.GetVirtualPath(requestContext, dict);
	return (path != null ? path.VirtualPath : null);
}

protected void AssertRouteUrl(string currentPage, string expectedUrl, 
	object routeData)
{
	var str = FindUrlToRoute(currentPage, routeData);
	Assert.AreEqual(expectedUrl, str, "URL was wrong!");
}

The sharp eyed among you will note that I am not actually calling Html.ActionLink() itself, but a different method, routes.GetVirtualPath. When you construct an action link, or when you use Url.Action(...) in your views, ASP.NET MVC ends up one way or another running your data through the GetVirtualPath method of your route table. You have to mock the Response.ApplyAppPathModifier method — a fact that wasn’t immediately obvious, and it took a bit of digging around in the System.Web.Routing assembly with Reflector to find out exactly what needed to be done.

You can then check to see whether you are getting the correct URL out by calling in to the AssertRouteUrl method as follows:

[Test]
public void TestBlogPath()
{
	AssertRouteUrl(
		/*
		 * currentPage is an app-relative URL, so it must be
		 * prefixed with a tilde (~). Note that this is required
		 * and must point to a valid route.
		 */
		"~/blog/2008/10/25",
		/*
		 * expectedUrl, on the other hand, is an absolute path,
		 * so it shouldn't.
		 */
		"/blog/2008/10/10",
		/*
		 * The route data. Note that you specify your controller and
		 * action here as the controller and action properties 
		 * respectively.
		 */
		new { 
			controller = "blog",
			action = "index",
			year = "2008",
			month = "10",
			day = "10"
		}
	);
}

Download: Unit testing route URL generation – Visual Studio solution