Testing the Untestable with Delegate Injection

My ASP.NET skills may be a bit rusty, but that’s not stopping me from working on a side project in ASP.NET MVC. While it has made significant strides in the 4.0 release, code like this demonstrates that ASP.NET still has a long way to go to improve testability.

public class AccountController : Controller
{
    ITwitterService _twitter;

    //constructor dependency injection
    public AccountController(ITwitterService twitterService)
    {
        _twitter = twitterService;
    }

    public ActionResult SignInWithTwitter()
    {
        //check for GetRedirectUrl and sets cookie
        Response.SetCookie(new HttpCookie("RedirectUrl",
            FormsAuthentication.GetRedirectUrl(string.Empty, false)));

        //build callback URL
        var callback_url_builder = new UriBuilder()
        {
            Host = Request.ServerVariables["SERVER_NAME"],
            Port = int.Parse(Request.ServerVariables["SERVER_PORT"]),
            Path = Url.Action("SignInWithTwitterCallback"),
        };

        //Helper funciton to invoke Twitter’s oauth/request_token REST endpoint
        var url = _twitter.GetRequestToken(callback_url_builder.ToString());

        //redirect to the URL returned from _twitter.GetRequestToken
        return Redirect(url);
    }

This code has several dependencies that are hard or impossible to test: FormsAuthentication, Request, Response and Url. Testing this code is a real pain in the ass. When I originally wrote this code, I bit the bullet and wrote said the PITA test code. But I couldn’t help thinking there must be a better way.

Clearly, in order to be able to test this code, I need to introduce points of abstraction that can be filled with mock implementations during unit test runs. I already have one such abstraction point – the _twitter field of AccountController is an ITwitterService instance that gets injected on construction. I have a “real” implementation that gets injected in production and a mock implementation that I manually inject in my tests.

In order to test the code above, I’ll need to wrap the calls into the untestable objects in some sort of injectable dependency that can be mocked out for tests.

C# being an OO language, typically we think of Dependency Injection in terms interfaces and classes. However, wrapping the untestables in interfaces and then implementing those interfaces is a lot of additional code. Instead of one injected dependency, the code above would need five injected dependencies. Furthermore, since objects are both the unit of dependency injection as well as the typical way the URL namespace is segmented, I also have to consider the dependencies of any other action methods on AccountController. That gets ugly fast.

Instead of thinking in terms of objects and interfaces, I wondered what DI might look like if we thought about dependencies in terms of delegates and anonymous lambdas? You know, functional programming?  It might look something like this:

Func<string> @GetRedirectUrl;
Action<HttpCookie> @SetCookie;
Func<NameValueCollection> @ServerVariables;
Func<string, string> @ActionUrl;

public ActionResult SignInWithTwitter()
{
    //check for GetRedirectUrl and sets cookie
    @SetCookie(new HttpCookie("RedirectUrl", @GetRedirectUrl()));

    //build callback URL
    var callback_url_builder = new UriBuilder
    {
        Host = @ServerVariables()["SERVER_NAME"],
        Port = int.Parse(@ServerVariables()["SERVER_PORT"]),
        Path = @ActionUrl("SignInWithTwitterCallback"),
    };

    //Call twitter.GetRequestToken
    var url = _twitter.GetRequestToken(callback_url_builder.ToString());

    //redirect to the URL returned from Twitter.GetRequestToken
    return Redirect(url);
}

(Note, I’m using the @ symbol as a prefix for injected delegates, in order to make it easier to pick them out of the code. Looks kinda odd, but it is valid C#.)

This is better in that it’s actually testable without requiring a metric crapload of test code to mock the ASP.NET intrinsics. However, this approach don’t have enough information to inject dependencies based on type alone. For example, the @GetRedirectUrl is a Func<string> (i.e. a function that takes no parameters and returns a string). However, FormsAuth FormsCookieName and DefaultUrl properties would also be represented as Func<string> delegates as well.

Most DI containers have support resolving dependencies by name and type, but that makes declaring dependencies much tougher and more fragile in my opinion. If you’re going to limit yourself to static typing write compiled code, you might as well let the compiler do as much heavy lifting as possible, right?

Also, wrapping each untestable method call in a delegate has made the explosion of dependencies problem even worse. SignInWithTwitter declares four new dependencies, the callback action (not shown) adds seven new delegate dependencies and the sign out action adds one, making a total of thirteen dependencies! (including the original ITwitterService). However, none of these twelve delegate dependencies are shared across action methods. So they aren’t really controller dependencies so much as action dependencies. So what if I went ahead and declared them as action dependencies directly?

public Func<ActionResult> SignInWithTwitter(
    Func<string> @GetRedirectUrl,
    Action<HttpCookie> @SetCookie,
    Func<NameValueCollection> @ServerVariables,
    Func<string, string> @ActionUrl)
{
    return () =>
    {
        //check for GetRedirectUrl and sets cookie
        SetCookie(new HttpCookie("RedirectUrl", GetRedirectUrl()));

        //build callback URL
        var callback_url_builder = new UriBuilder
        {
            Host = ServerVariables()["SERVER_NAME"],
            Port = int.Parse(ServerVariables()["SERVER_PORT"]),
            Path = ActionUrl("LogOnCallback"),
        };

        //Call twitter.GetRequestToken
        var url = _twitter.GetRequestToken(
            callback_url_builder.ToString());

        //redirect to the URL returned from Twitter.GetRequestToken
        return Redirect(url);
    };
}

SignInWithTwitter is now a function that takes four delegates and returns a delegate – we’re really down the functional programming rabbit hole now!

The benefit of this approach is that I can make tradeoffs as I see fit between controller and action dependencies. ITwitterService is still injected via the AccountController constructor since it is used by two of the three Account actions. Dependencies only used by a single action can be scoped to that specific action so that only tests for a given action method have to mock them out. And testing this is a breeze compared to having to mock out intrinsic ASP.NET objects.

[Fact]
public void returns_redirect_result_with_getrequesttoken_url()
{
    //inject controller dependencies
    var twitter = new Mock<Models.ITwitterService>(MockBehavior.Strict);
    twitter.Setup(t => t.GetRequestToken(It.IsAny<string>()))
        .Returns("http://fake.twittertest.local");
    var controller = new AccountController(twitter.Object);

    //inject action dependencies
    Func<string> @getRedirectUrl = () => "/fake/redirect/url";
    Action<HttpCookie> @setCookie = c => { };
    Func<NameValueCollection> @serverVariables =
        () => new NameValueCollection()
        {
            {"SERVER_NAME", "testapp.local"},
            {"SERVER_PORT", "8888"}
        };
    Func<string, string> @actionUrl = url => "/fake/url/action/result";
    var action = controller.SignInWithTwitter(@getRedirectUrl,
        @setCookie, @serverVariables, @actionUrl);

    //Invoke action
    var result = action();

    //Validate
    var redirectResult = Assert.IsType<RedirectResult>(result);
    Assert.Equal("http://fake.twittertest.local", redirectResult.Url);
}

I could make this code even smaller by moving the action dependencies out to be test fixture class fields. Assuming you write multiple tests for each action method, this allows you to reuse the mock action delegates across multiple methods. If I want to do negative testing, I can easily define test-specific delegates that throw exceptions or return unexpected values.

Of course, the down side to this approach is that MVC has no idea what to do with an action method that returns Func<ActionResult>. I could envision support for this pattern in MVC someday, though we’d need a robust solution to the type+name dependency issue I described above. For now, I will simply wrap the delegate injection version (aka the testable version) of the action in a non-testable but MVC compatible version that injects the right delegate dependencies.

public ActionResult SignInWithTwitter()
{
    return SignInWithTwitter(
        () => FormsAuthentication.GetRedirectUrl(string.Empty, false),
        Response.SetCookie,
        () => Request.ServerVariables,
        Url.Action)();
}

Since I’m using the untestable intrinsics, I can’t write any tests for this method. However, it’s nearly declarative because the anonymous delegates I’m injecting are closing over the untestable intrinsics. Personally, I’m willing to make the tradeoff of having an declarative yet untestable wrapper action method in order to get the delegate injected easy-to-test version of SignInWithTwitter that has the real implementation.

Morning Coffee 166

Yes, I realize it’s been a while. I tried in vain to catch up with my blog reading after my Hawaii vacation and finally just gave up and hit “mark all as read”.

Dynamic Languages

  • There’s a new version of the DLR hosting spec available (doc, pdf). The DLR implementation is still in motion, so there are some inconsistencies between the spec and the code, but the spec should give you the high level overview you need if you want to host DLR languages inside your app.
  • Oleg Tkachenko recently joined the dynamic languages team. He’s the creator of the Interactive IronRuby Web Shell, an IronRuby version of Try Ruby. Of course, it’s not as cool as using SL2to execute the code directly in the browser. Michael Foord has his Python in the Browser and my teammates John and Jimmy demoed a Silverlight version of Try Ruby @ TechEd.
  • Jim Deville, also of the dynamic languages team, recently started blogging.
  • I have a new boss, Dave Remy. He doesn’t have a blog – yet – but you can follow him on Twitter as daveremy. When Twitter is actually working that is.
  • There’s a new homepage/wiki for IronRuby though I’m not sure why there’s a picture of Matz wearing a Python shirt on the home page.
  • My teammate Jimmy Schementi provides some “continued hope” for a better (heck, I’ll take current) ASP.NET and ASP.NET MVC story for DLR languages.
  • Via Michael Foord, sounds like IronClad is making good progress. V0.4 can run the bz2 module “in its entirity” (maybe run a spellcheck on your site, guys?) and now apparently, it’s now able to load numpy.core. Very exciting!

Other Stuff

  • Pat Helland, who has blogged even less than me for the past few months, has a post up about controller and doers in the IT department. After 18 months in MSIT, put me in the doer camp, please.
  • The F# team has pushed out a spec for v1.9.4 of the language. Don Syme says it’s not official, but it’s a huge improvement over the old informal spec
  • Speaking of F#, my friend Matthew Podwysocki recently published FsTest, a testing DSL for F#. I wrote about F# unit testing as part of my PEG parsing series, and I really like the direction Matthew has taken this project. You can pull it down from CodePlex.
  • When I did my PEG talk @ Lang.NET, Gilad Bracha mentioned I should check out oMeta. It looks really cool, though with the job change I haven’t had the time to play with it. Now I discover that Jeff Moser is working on a version for CLR called oMeta# that I’ve got to spend some time with. And in the comments to that post, I discovered pyMeta from Allen Short, though it apparently doesn’t work on IronPython (must investigate why).
  • James Kovacs introduces psake, a PowerShell based build automation tool which uses a rake-inspired internal DSL syntax similar to one I blogged last year. I’d love to see this take off, but given MSBuild’s tool integration, I wonder if that’s feasible.
  • I upgraded my home wireless network almost exactly a year ago. I’ve been happy with the range and coverage, but not so happy with the Buffalo Tech firmware. The built-in DHCP server is pretty flaky. So I upgraded to the open-source Tomato firmware. Upgrade was smooth, though I did need to reset my cable modem. But even that was smooth – Comcast has an automated service for that now,

Morning Coffee 160

I took most of last week between jobs and have spent much of this week getting machines setup, access to builds, etc. Furthermore, RSS Bandit ate my feedlist and I am still soldiering on sans mobile phone so I was pretty much unconnected for about a week and a half.

IPy Stuff

  • Laurence Moroney demonstrates how to configure a web site project in VS08 to use Dynamic Silverlight’s development web server Chiron. I looked at turned it into an exported template, but I think the Start Options are stored in the suo file and I’m not sure how to include that in the template. Maybe it could be set w/ a macro or at worst a GAX recipe?
  • If you’re a regular reader, you might as well get used to the name “Michael Foord”. He’s a developer @ Resolver Systems, makers of the IPy based Resolver One app/spreadsheet hybrid I’ve written about before. He’s also the author of the upcoming IronPython in Action book and the maintainer of Planet IronPython and the IronPython Cookbook. I’m going to try very hard to only link to Michael at most once per day. Frankly, that’ll be tough.
  • Today’s Michael Foord Link: Michael turned his PyCon talk on IPy + SL2 into a series of articles entitled IronPython & Silverlight 2 Tutorial with Demos and Downloads.
  • Ken Levy (who now sits just down the hall from me) clued me into the 1.0 release of IronPython Studio, which is a free IDE based on the VS08 Shell for IronPython (based on code from the VS SDK). Big new feature in this release is support for the integrated VS08 Shell, which means it’ll snap into your existing VS08 installation (well, not express) rather than forcing you to install the 300 MB isolated shell.

Other Stuff

  • Caps had a BIG win last night when they needed it most. Now they’re tied with Carolina for the SE division lead, but they lose the tiebreaker so unfortunately, they can’t make the playoffs without help. ‘Canes have to head back home last night to play Tampa Bay, they have to win tonight and Friday to clinch. Loss in either gives the Caps control of their own destiny. Caps are only one game back of Ottawa, Boston and Philly, none of whom have played well down the stretch. It does mean I have to root for the frakking Penguins to beat Philly, twice.
  • Now that I’m in a job where I’ll be traveling occasionally, I really appreciated Scott Hanselman’s travel tips, though I’m not sure “Don’t look like a schlub” is in the cards for me.
  • Unless you’ve been living under a rock, you’re probably aware that Scott Guthrie blogged that the ASP.NET MVC Source Code is available on CodePlex. The project name is “aspnet” not “aspnetmvc” which makes me wonder if they might release the source to more ASP.NET stuff over time.
  • Speaking of Scott Guthrie, today he blogged about unit testing in Silverlight. Jeff Wilcox appears to have the definitive post on the subject, including links to the SilverLight testing framework (it’s included in the SL Controls source code release). He also provides a prebuilt “Silverlight Test” project template for easy download. Personally, I really like the in-browser test runner. I wonder how hard it would be to hook that up to DySL so you could write your tests in IPy? (given that IPy doesn’t have attributes, I’m guessing there’d be at least a bit of work involved in making this happen)
  • Speaking of Silverlight, apparently the next version of Windows Mobile (i.e. 6.1) will support it. Since I’m in the market for a new phone anyway, I’m thinking of getting one of these. Also, it’s nice to see a marketing site for WM 6.1 using Silverlight instead of Flash like WM 6.0 marketing site does.(via LiveSide)
  • Ted Neward turns the news that MSFT is releasing XAML under the OSP into a long and fascinating history lesson that is well worth the read. I’m going to skip commenting on it, beyond advising you dear reader to read this if you haven’t already, except to wonder: how many sides does a “Redmondagon” have?

Practical F# Parsing: Unit Testing

Now that I have functions to access the parse buffer, I better write some tests for them. Yes, I realize I should have written the tests first, but the articles flow better this way.

I’ve written before that one of the benefits to side-effect free functional programming is that it makes unit testing a breeze. But I still need some type of xUnit testing framework. I could write my own native F# xUnit framework, but given the availability of mature xUnit frameworks on .NET, I’d really rather just use one of them.

Traditionally, I’ve used NUnit or Visual Studio’s unit testing framework, but they’re designed to work with OO languages like C#. In order to use them from F#, we have to use the OO features of F#. Here’s an example of some F# unit tests using NUnit.

type [<TestFixture>] parser_tests =
    class
        new () = {}

        [<Test>]
        member this.test_NC() =
            let Some(c,text) = NC !!"test"  
            Assert.Equal(c, 't')
            Assert.Equal(text, !!"est")

        [<Test>]
        member this.test_NC_empty_string() =
            let ret = NC !!""  
            Assert.Equal(None, ret)
    end

While this works, there’s an awful lot of extraneous text needed to make this work. Test functions need to be methods on a Test Fixture class (note, F# uses [< >] to indicate attributes) and that class needs a default constructor. F# doesn’t add one by default, so we have to do so manually. And every test function needs to be marked with “member this”.

I’d really rather write tests that looks like this:

[<Test>]
let test_NC =
    let Some(c,text) = NC !!"test"  
    Assert.Equal(c, 't')
    Assert.Equal(text, !!"est")

[<Test>]
let test_NC_empty_string =
    let ret = NC !!""  
    Assert.Equal(None, ret)

That’s a lot more straightforward. If only I could write my test code like that…

It turns out there’s a new kid on the .NET unit testing block. xUnit.net is the brainchild of Jim Newkirk (one of the original NUnit developers) and Brad Wilson (aka the .NET Guy). Among other things, xUnit.net does away with the TestFixture attribute. All public methods in all public classes are checked for tests in xUnit.net.

Since we don’t need the TestFixture, does that mean I can write the tests as F# functions if I use xUnit.net? Not quite. xUnit.net only checks for public instance methods on the public classes in a test assembly. But F# functions get compiled as static methods. Luckily, xUnit.net is simple enough to change. I submitted a patch to xUnit.net that enables it to find both static and instance test methods (and to skip creating and disposing an object instance for static test methods). I’m hoping it will be accepted and ship as part of their next release. Until then, I’m running my own private build with those changes included.

Now that I’ve settled on a unit test framework, let’s look at some tests. For my parser solution, I have two projects: PegParser and PegParser.Tests. The tests project depends both on the PegParser assembly as well as xunit.dll, so I need to set a reference to both in my project. F# projects in VS don’t have the References node in the project tree, you have to either add the references on the project property page or directly within the code. Not sure which is better, but it’s easier to show the code syntax:

#R @"....xUnit.netMainxunitbinDebugxunit.dll"
#R @"..PegParserpegparser.dll"

open Xunit
open Parser

The #R compiler directive is used to reference an external assembly. F#’s open statement acts like C#’s using statement, so I can reference types without specifying their full namespace. You’ll notice that the parser is implemented in a dll called pegparser.dll while the namespace is simply Parser. Actually, it’s not really a namespace. If you open PegParser.dll in Reflector, you’ll notice that Parser is actually a type, and the functions are all implemented as static methods. F# hides that from you, though you’d have to know that if you wanted to invoke the parser from C# or VB.net. By default, F# uses the filename as the namespace/class name and I haven’t changed that default in my parser code (though I probably should).

Once we’ve referenced the correct assemblies, I need to write the tests. Here are two tests for NC (aka Next Char) function I wrote in the last post.

[<Fact>]
let test_NC_empty_string () =
    let ret = NC !!""
    Assert.Equal(None, ret)  

[<Fact>]
let test_NC_simple_string () =
    let Some(c,text) = NC !!"test"
    Assert.Equal(c, 't')
    Assert.Equal(text, !!"est")

You’ll notice this code is almost identical to my wish test code above. Almost. There are a few syntax changes – In xUnit.net, tests are called facts and Assert.AreEqual is simply Assert.Equal. I’ve also had to add empty parentheses after each test function name. Remember that functions in FP are like math functions. If there’s no independent value to pass in, the result of a math function is is constant. F# compiles parameter-less functions as static properties instead of a static methods. In order to make the test functions compile as static methods, we have to pass in at least one parameter. In F#, the unit type is the equivalent of the void type in C#. Unit has exactly one valid value – the empty parens. Adding the empty parens to the parameter list of the test functions ensures they get compiled into static methods.

Note, it’s really really easy to forget to add those empty parens. If you don’t add them, the code will still compile, but the tests won’t be found or run. I’ve been bit by that once already, so if you have a bunch of tests not running, make sure they have the empty parens!

So each test method feeds a parse buffer (converted from a string with the custom !! operator) into the NC function and makes assertions about the result. In the first test, NC should return None if the parse buffer is empty, so I simply compare the function result to None via Assert.Equals. In the second test, I use F#’s pattern matching capability to assign the result of NC to the value Some(c,text). Basically, this is doing simple pattern matching to bind the two value names to the two parts of the tuple returned from NC. Those two values are then asserted to be a specific values as you would expect.

Note, in the current version of F#, the line let Some(c,text) = NC !!"test" yields two warnings. The first (FS0062) warns that a future version of the language will require parens around Some(c,text). I sure hope they change their minds on this, since active patterns are already so parens-heavy. The second (FS0025) warns that this is an incomplete pattern match. If NC returns None, the pattern wont match and the function will throw a MatchFailureException. Of course, since these are unit tests, that’s exactly the behavior I want! Given the nature of these warnings, personally, I turn them both off (only in my unit tests, mind you). This is done via the #nowarn compiler directives at the top of the file.

#nowarn "25" //Turn off Incomplete Pattern Match warning
#nowarn "62" //Turn off Some contruct needs parens warning

Obviously, there are more tests than just these (though my total code coverage is pretty poor, shame on me) but they’re all pretty similar. As you can see, there’s tests are very straight forward. The nature of FP functions makes them fairly simple to test, and xUnit.net (with a couple of minor changes) makes it easy to write your unit tests in F#.

Morning Coffee 99

  • Mladen Prajdic has a great post on handling a database in your unit tests. He mentions NDbUnit but seems mostly to favor SQL 2005′s database snapshot feature. He’s got sample code for creating and restoring a snapshot. (via DNK)
  • Microsoft Robotics Studio 1.5 released yesterday. Tandy Trower – GM of the Robotics group – has the details on what’s new.
  • Herb Sutter has a new column in Dr. Dobbs on concurrency. First up, “building a consistent mental model for reasoning about concurrency”. Sounds like a must read column. (via LtU)
  • Scott Hanselman describes “Sez You Architecture”. I wonder, do architecture ninjas get to wear a Shinobi shozoku?
  • From the Not Everyone Agrees With DevHawk Dept.: Libor Soucek disagrees with me and thinks that durable messaging should be avoided. I had a hard time following Libor’s logic but needless to say, I disagree with his disagreement. He writes that one of the reasons to use DM is for “Cooperating on transaction with external system”. While multiple systems may be cooperating on a business transaction, in no way do I believe they are going to cooperate on a database transaction. But since he started talking about the DTC, I suspect we’re talking past each other. Libor, drop me a line and we can discuss further.