Slash Boxes
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Mark Leighton Fisher (4252)

Mark Leighton Fisher
  (email not shown publicly)

I am a Systems Engineer at Regenstrief Institute []. I also own Fisher's Creek Consulting [].
Friday June 29, 2007
12:05 PM

.NET Class Mocking Requires an Interface: A Code Smell?

[ #33638 ]

I want to follow up a comment I made on Roy Osherove's blog about how a .NET class must have an interface before you can mock that .NET class. This interface-before-mocking requirement seems like a Code Smell to me, or maybe an Architecture Smell.

.NET interfaces, like Perl 6 roles, to me should be used when you need to share behavior between otherwise unrelated objects (a Pet Dog and a Pet Cat, for instance). Requiring a .NET class to have an interface before it can be mocked seems like Microsoft is not just exposing an implementation detail, but rather forcing it down the developers throats.

Why should this be the case? The only explanations I can come up with are:

  • Requiring an interface means you cannot override the .NET String class (similarly to String being final in Java); or
  • The .NET developers never considered mocking as an important capability.

Ever since I discovered the power of mock objects (to the point of writing Test::MockDBI), I realized that mock objects are the logical next step after plain code stubs, as mock objects let you simulate the behavior of the outside world so you can easily test your code without building a 1.1 billion-row test database (for example). Almost any time your code needs to communicate with the outside world, you can test first with mock objects as a mock-up of the real world objects. For much testing (esp. automation-assisted testing like Test::More provides), you do not need the objects outside of the class you are testing to respond to arbitrary inputs you just need them to respond to the particular inputs your test code will end up generating. Mock objects are perfect for this use, as their behavior will match how the real objects behave (within the limits of how you program the mock objects, of course).

I can think of a couple of ways that might work around this current limitation, if the mocking-requires-interface decision was because system classes should not be overridden without the user's consent:

  • Allow mocking, but only from within the same assembly. This has the virtue of keeping the testing and testee code together. I'm not sure how this would interact with ILMerge, though.
  • Allowing mocking only of classes in unsigned assemblies (assemblies without a Strong Name). I think this also undercuts the overriding of system classes, as system classes (defined by me here as assemblies shipped by Microsoft that always live in the Global Assembly Cache (GAC)), could not be overridden by mocking, as you cannot ship your own assembly signed with Microsoft's Strong Name key.

To sum up: Someway, somehow Microsoft's .NET development team should find a way around this "you need an interface before you can mock" limitation. .NET is clean in many ways, so it would be good for .NET to be rid of the interface-before-mocking requirement.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
More | Login | Reply
Loading... please wait.
  • That's the one thing I hate about writing NUnit tests...not being able to Mock when I need to without it turning into a science fair project.

    The later verison of TypeMock.NET do allow you to mock classed without interfaces. Last I checked, it still had a problem with mocking a superclass of a current class, or maybe that's a superclass that is in unmanaged code.

    Either way, much harder than in Perl TDD...and I sure do miss local() sometimes too.
    • I like that – mocking a .NET class as a science fair project. That kind of annoyance is what prompted the essay, as I think the .NET team just didn't think through all the implications of their design.