Background: Changing Class and Instance Members At Runtime

One of the nifty things about dynamic languages like JavaScript, Ruby, and others is the fact that you can manipulate aspects of class prototype information (i.e. the Class itself -- its interface) of all instances of that class, as well as individual instances.

For instance, we can do something like this in JavaScript:

function Pegleg(typeName)
{                    
    this.name = typeName;
}

var hungry = new Pegleg("I'm hungry");
var thirsty = new Pegleg("I'm thirsty");

// Add a new method to all current and future instances
Pegleg.prototype.ToPirateSpeak = 
    function(){ return this.name + ", Arrr!"; }

document.writeln(hungry.ToPirateSpeak() + "<br/>");
document.writeln(thirsty.ToPirateSpeak() + "<br/>");

// Add a new method to this specific instance
hungry.ToAngryPirate = 
    function(){ return "Avast, " + this.name + ", Yarrr!"; }
        
document.writeln(hungry.ToAngryPirate() + "<br/>");

Which will print out:

I'm hungry, Arrr!
I'm thirsty, Arrr!
Avast, I'm hungry, Yarrr!

This is pretty handy, especially when doing it carefully and with great consideration using a framework like Prototype to help you stay focused on good OO-like design principles. This sort of thing comes in pretty handy when doing unit tests, as you don't have go through a lot of hoops to do mocking in you unit tests, since you change the interface on the class-under-test and its dependencies at run-time/test-time.

Of course, this sort of thing isn't possible in C#, which is why we need to use interface-based programming. Well, there's a lot of other good reasons to use interface-based programming in many circumstances, but there are quite a few times where interfaces aren't needed except in order to facilitate mock-based testing.

But wait, all hope is not lost...

We can achieve something similar to this effect in C# by forgoing our current understanding of how methods work in C# classes. By using anonymous delegates, we can achieve similar capabilities which let us perform mock-based testing without having to clutter up all our classes with interfaces.

Consider the following class:

public class Tree
{
    private WaterSource _waterSource;
    private NutrientSource _nutrientSource;

    public Tree(WaterSource waterSource, NutrientSource nutrientSource)
    {
        _waterSource = waterSource;
        _nutrientSource = nutrientSource;
    }

    public int Height{ get; set; }
    public virtual bool TakeWater()
    {
        return _waterSource.TakeSome();
    }

    public virtual bool TakeNutrients()
    {
        return _nutrientSource.TakeNutrients();
    }

    public virtual void Grow()
    {
        if (TakeWater() && TakeNutrients())
            Height++;
    }
}

This approach isn't bad, but it doesn't leave me a lot of options for unit testing Tree.  If WaterSource.TakeSome() is not a virtual method, then I cannot mock it using something like Rhino.Mocks.  Now my unit tests necessarily have to worry about what WaterSource.TakeSome() will return under any given condition.  This makes for leaky, complicated tests. What I'd like to do is somehow override TakeSome() and provide my own implementation so I can make it return what I want in my unit test to simulate specific known conditions.

Currently, one of the best ways of doing this is to create an interface (i.e. IWaterSource), have WaterSource implement it, and then use a mocked instance of IWaterSource to simulate desired behavior.  But what if I don't want IWaterSource because I'll never use it for anything else?

Perhaps we could try something like this:

BEFORE

public class WaterSource
{
    public bool TakeSome()
    {
        return true;
    }
}

AFTER

public class WaterSource
{
    public TakeSomeFunc TakeSome = () =>{ return true; };
    public delegate bool TakeSomeFunc();
}

Now, with this I can change the implementation of a given WaterSource implementation at runtime. So in my test I can do something like this:

[Test]
public void Should_not_change_height_if_no_water_available()
{
    WaterSource water = new WaterSource();
    NutrientSource nutrients = new NutrientSource();
    Tree tree = new Tree(water, nutrients);
    Assert.That(tree.Height, Is.EqualTo(0));

    // Mock the TakeSome method to return the desired result
    water.TakeSome = () => { return false; };
    tree.Grow();

    Assert.That(tree.Height, Is.EqualTo(0));
}

What about 'prototype' or class-level overrides?

At this point, all we've done is addressed the instance-level problem, we haven't touched on the class-level problem (the '.prototype' situation in JavaScript parlance).

If we change our TakeSome definition to call a static, class-level prototype implementation, then we can achieve a class-level override of the method, but still allow for individual method-level overrides:

public class WaterSource
{
    public static TakeSomeFunc TakeSomePrototype = () => { return true; };

    public TakeSomeFunc TakeSome = () => { return TakeSomePrototype(); };

    public delegate bool TakeSomeFunc();
}

Now we can test changing all instances, and changing an individual instance and ensure that they work properly:

[Test]
public void This_is_a_sample_test_and_not_what_I_would_normally_do()
{
    WaterSource water1 = new WaterSource();
    WaterSource water2 = new WaterSource();
    NutrientSource nutrients = new NutrientSource();

    Tree tree1 = new Tree(water1, nutrients);
    Tree tree2 = new Tree(water2, nutrients);

    // Change all instances and mock the result
    WaterSource.TakeSomePrototype = () => { return false; };

    tree1.Grow();
    tree2.Grow();

    Assert.That(tree1.Height, Is.EqualTo(0));
    Assert.That(tree2.Height, Is.EqualTo(0));

    // Now change the one instance back, and try again
    water2.TakeSome = () => { return true; };

    tree1.Grow();
    tree2.Grow();

    Assert.That(tree1.Height, Is.EqualTo(0));
    Assert.That(tree2.Height, Is.EqualTo(1)); //<-- It Grew!
}

What about inheritance?

This method can still work even in inheritance scenarios. Consider the following SaltWaterSource subclass:

public class SaltWaterSource : WaterSource
{
    public SaltWaterSource()
        : base()
    {
        // Override default implementation
        TakeSome = () => { return WaterIsAvailable(); };
    }

    public bool WaterIsAvailable()
    {
        // Salt Water is only avilable on Tuesday, I don't know why
        // this is what the customer asked for
        return (DateTime.Now.DayOfWeek == DayOfWeek.Tuesday);
    }
}

And it works in the test:

[Test]
public void This_is_a_sample_test_and_not_what_I_would_normally_do()
{
    SaltWaterSource saltWater = new SaltWaterSource();
    NutrientSource nutrients = new NutrientSource();

    Tree tree = new Tree(saltWater, nutrients);

    saltWater.TakeSome = () => { return false; };

    tree.Grow();

    Assert.That(tree.Height, Is.EqualTo(0));
}

One problem with this approach is that I won't be able to override the prototype TakeSome for ONLY SaltWaterSource instances. If I want to add more prototype-ability to SaltWateSource implementations, I could do something like this:

public class SaltWaterSource : WaterSource
{
    public static TakeSomeFunc TakeSomeSaltWaterPrototype =
        () => { return (DateTime.Now.DayOfWeek == DayOfWeek.Tuesday); };

    public SaltWaterSource()
        : base()
    {
        TakeSome = () => { return TakeSomeSaltWaterPrototype(); };    
    }
}

Note that I didn't have to redefine TakeSome. I was able to override it via the c'tor and thus preserve the polymorphism aspect of C# classes.

And then our test looks about the same, except just with a SaltWaterSource:

[Test]
public void This_is_a_sample_test_and_not_what_I_would_normally_do()
{
    SaltWaterSource water1 = new SaltWaterSource();
    SaltWaterSource water2 = new SaltWaterSource();
    NutrientSource nutrients = new NutrientSource();

    Tree tree1 = new Tree(water1, nutrients);
    Tree tree2 = new Tree(water2, nutrients);

    // Change all instances and mock the result
    SaltWaterSource.TakeSomeSaltWaterPrototype = () => { return false; };

    tree1.Grow();
    tree2.Grow();

    Assert.That(tree1.Height, Is.EqualTo(0));
    Assert.That(tree2.Height, Is.EqualTo(0));

    // Now change the one instance back, and try again
    water2.TakeSome = () => { return true; };

    tree1.Grow();
    tree2.Grow();

    Assert.That(tree1.Height, Is.EqualTo(0));
    Assert.That(tree2.Height, Is.EqualTo(1)); //<-- It Grew!
}

Workaround for ASP.NET MVC Controllers

One nifty side-effect of this method is that we can now effectively test controllers in the ASP.NET MVC framework without having to do the subclass-for-test approach (as illustrated by Phil Haack on his blog) which is currently required due to a design flaw in the RenderView() method implementation in the Preview release of the MVC bits that are available at the time of this writing.

I prefer not having to subclass my Controllers just to test them, so I was looking for a way to keep the controllers sound without having to contort too horribly in order to make them testable. I came up with this adaptation to the standard HomeController that comes with every new "ASP.NET MVC Application" project wizard in Visual Studio 2008:

public class HomeController : Controller
{
    public RenderViewProc CallRenderView;

    public HomeController()
    {
        CallRenderView = (v,d) => { this.RenderView(v, d); };
    }

    [ControllerAction]
    public void Index()
    {
        RecipeRepository repo = new RecipeRepository();
        
        CallRenderView("Index", repo.FindAllReceipes());
    }

    [ControllerAction]
    public void About()
    {
        CallRenderView("About", null);
    }
}

public delegate void RenderViewProc(string viewName, object viewData);

 

Incidentally, my RecipeRepository also uses the anonymous delegate instance method approach so that I can mock it for testing as well. So my test ends up looking like this:

[Test]
public void Should_get_list_of_recipes_and_invoke_the_index_action()
{
    bool findAllCalled = false;
    bool valueSet = false;

    HomeController controller;
    // Record
    {
        // Mock the recipe find all method
        RecipeRepository.FindAllRecipesPrototype = () => { findAllCalled = true; return null; };
        controller = new HomeController();
        controller.CallRenderView = (v, d) => { valueSet = true; };

        // Sanity check
        Assert.That(findAllCalled, Is.False);
        Assert.That(valueSet, Is.False);
    }

    // Playback
    {
        controller.Index();
    }

    // Test expectations -- similar to VerifyAll() w/ Rhino.Mocks
    Assert.That(findAllCalled, Is.True);
    Assert.That(valueSet, Is.True);
}

As you can see here, I was able to mock the FindAllReceipes() method and the CallRenderView method to totally negate the RenderView() non-mockable dependency problem.

Likewise, I was able to achieve a similar set of functionality to Rhino.Mocks Expect.Call() record/playback system.  It's not as robust as Rhino.Mocks, but for this purpose it isn't so bad.

What does this all mean?

I'm not sure where to go from here, or what this means. I haven't gone much further than what you see here.  It seems like it solves a lot of the current problems around Interface-explosion and dynamic typing vs. static typing, etc.  I'm sure I've probably missed a death-knell here and I'm curious to know what it would be. Performance? OO-fundamental violation? Compiler confusion?  Any obvious errors that you can see?

I'm going to keep playing with this for awhile and see if I can see any buzz-kills, but so far I'm thinking that this might be a valid approach for certain situations and solving a few specific problems without having to add interfaces to everything