C# 4.0 Duck Typing and mocking extension methods
Seeing some of the early blog posts from people who are at PDC, I have thus far been paying most attention to the information starting to come out about C# 4.0. In particular, this focus will look at Dynamic Lookup and the dynamic type. In particular, this should be able to be used to solve a problem with mocking objects where you are using extension methods.
As a reminder, extension methods were introduced in C# 3.0 and enable you to 'add' methods to a class, even if that class is beyond your direct control, or is a sealed class. The canonical example would be adding a method such as 'Reverse' to the (sealed) String class. This would typically look something like (source: Wikipedia):
1: public static class Utility
2: {
3: public static string Reverse(this string input)
4: {
5: char[] chars = input.ToCharArray();
6: Array.Reverse(chars);
7: return new String(chars);
8: }
9: }
All fairly standard so far and nothing particularly dramatic. The interesting question comes if (for example) you were Unit Testing an application involving a class with an extension method that you want to mock. In fairness, this might not be going to happen every day, but is in fact a very similar problem to that that Phil Haack faced with trying to mock the HttpContext class. In both cases, we are faced with a method that you cannot mock. In Phil's case, because the classes HttpRequest and HttpResponse are sealed, and this case, the fact that the extension method isn't actually part of the class means that a mocking framework cannot offer an override for it.
Let us create a simple example, using the above utility class:
1: public class Program
2: {
3: static void Main(string[] args)
4: {
5: Demo demo = new Demo(new TextProvider());
6: Console.WriteLine(demo.Example());
7: Console.ReadKey();
8: }
9: }
10:
11: public class Demo
12: {
13: ITextProvider Provider;
14:
15: public Demo(ITextProvider input)
16: {
17: this.Provider = input;
18: }
19:
20: public string Example()
21: {
22: return Provider.Reverse();
23: }
24: }
25:
26: public class TextProvider : ITextProvider
27: {
28: public string Text
29: {
30: get { return "Monkey"; }
31: }
32: }
33:
34: public interface ITextProvider
35: {
36: string Text { get; }
37: }
38:
39: public static class Util
40: {
41: public static string Reverse(this ITextProvider input)
42: {
43: char[] chars = input.Text.ToCharArray();
44: Array.Reverse(chars);
45: return new String(chars);
46: }
47: }
Apologies for the rather contrived example, but it should serve the purposes of illustration. Now let us set up an attempt to test the Example method. In the example below I will be using xUnit.net, but which framework is used is rather unimportant.
1: public class DemoTest
2: {
3: [Fact]
4: void ExampleReversesMonkey()
5: {
6: // Arrange
7: Demo demo = new Demo(new TextProvider());
8:
9: // Act
10: string result = demo.Example();
11:
12: // Assert
13: Assert.Equal("yeknoM", result);
14: }
15: }
And this compiles and runs just fine, and we pass the unit test, which is all good. But suppose that rather than passing a real 'TextProvider', we want to pass in a mocked version. Using Moq, we might expect to modify the test to look something like this:
1: [Fact]
2: void ExampleReversesMockedString()
3: {
4: // Arrange
5: var mock = new Mock<ITextProvider>();
6: mock.Expect(x => x.Text).Returns("Monkey");
7: Demo demo = new Demo(mock.Object);
8:
9: // Act
10: string result = demo.Example();
11:
12: // Assert
13: Assert.Equal("yeknoM", result);
14: }
All fine so far - this builds and runs without any problem. So lets take it a stage further and rather than just mocking the Text property, let's mock the Reverse method as well by adding this line:
1: mock.Expect(x => x.Reverse()).Returns("yeknoM");
Suddenly everything's changed. Instead of running successfully, we now get a run time exception from xUnit.net telling us "Invalid expectation on a non-overridable member: x => x.Reverse()". And indeed there is no way for us to mock an extension method. But fear not, help looks to be shortly at hand. The dynamic lookup features of C# 4.0 will nicely address this problem, if we want our class to remain unit testable. Obviously details of exactly how the syntax is going to work are a little sketchy at this stage, but the idea would be to change the Example method of the Demo class to be something like:
1: public string Example()
2: {
3: dynamic d = Provider;
4: return d.Reverse();
5: }
And with basically no more changes, we should be back in business. The exact way that we mock the object will have to change since the mocking framework must not attempt to override the method, but we have at least opened up options for ourselves again.