views:

2463

answers:

9

Mocking sealed classes can be quite a pain. I currently favor an Adapter pattern to handle this, but something about just keeps feels weird.

So, What is the best way you mock sealed classes?

Java answers are more than welcome. In fact, I would anticipate that the Java community has been dealing with this longer and has a great deal to offer.

But here are some of the .NET opinions:

A: 

Is there a way to implement a sealed class from an interface... and mock the interface instead?

Something in me feels that having sealed classes is wrong in the first place, but that's just me :)

Jon Limjap
I think sealed classes are great ... the problem is testing. It stinks that we have to change our entire design because of limitations in testing .NET projects. In many cases D.I. is simply a way to get around the fact that static classes/methods are hard to test.
Jess
+2  A: 

My general rule of thumb is that objects that I need to mock should have a common interface too. I think this is right design-wise and makes tests a lot easier (and is usually what you get if you do TDD). More about this can be read in the Google Testing Blog latest post (See point 9).

Also, I've been working mainly in Java in the past 4 years and I can say that I can count on one hand the number of times I've created a final (sealed) class. Another rule here is I should always have a good reason to seal a class, as opposed to sealing it by default.

abyx
I would argue that you should have a good reason *not* to seal a class. Leaving a class open means you need to think about how it will be used by inheritors, which opens up a floodgate of decisions about all the code in the class (virtuality, protected properties or private member variables, etc.) It is *hard* to properly design a class for inheritance. You shouldn't be able to extend a class just for extension's sake; derivation should mean something specific to the problem being modeled. Otherwise, favor composition instead.
Bryan Watts
Bryan - so how would you mock a sealed class then? I agree with you from a theoretical standpoint, but if you write something dependent on your sealed class then your tests depend on the sealed class as well.
Jess
+8  A: 

For .NET, you could use something like TypeMock, which uses the profiling API and allows you to hook into calls to nearly anything.

Haacked
+1. Use the right tools. Don't let tools dictate you how you should do things. APIs are for people, not for tools - design them as such. Use DI and interfaces and full decoupling where it makes sense, not just because you need it for testing tools.
Pavel Minaev
Pavel - the problem is that the "Right" way in .NET usually leads you down a path of 'Use TypeMock to test'. Following a path where there is only one testing tool available doesn't seem great either.
Jess
Some people might not like paying $80 a month for a test framework.
Matt Grande
I think Moles allows you to work with sealed classes - and if you have a MSDN subscription, it's free.
Mathias
+1  A: 

The problem with TypeMock is that it excuses bad design. Now, I know that it is often someone else's bad design that it's hiding, but permitting it into your development process can lead very easily to permitting your own bad designs.

I think if you're going to use a mocking framework, you should use a traditional one (like Moq) and create an isolation layer around the unmockable thing, and mock the isolation layer instead.

Brad Wilson
Not slapping interfaces on everything in sight just because you need them because of deficiencies of your testing tools is not bad design. In fact, quite the opposite - it's _sane_ design that is about design, not about conforming to your tools. I swear, sometimes I think that TDD as it's often dogmatically practiced should really be called "tools-driven design". Also see http://weblogs.asp.net/rosherove/archive/2008/01/17/is-typemock-too-powerful-will-it-kill-design-for-testability.aspx
Pavel Minaev
Pavel - do you have another tool other than TypeMock that can provide this type of testing? Testing classes built with sane designs (e.g. using static methods, new calls in code, limiting interfaces to where multiple implementations are needed, etc) are often next to impossible to test.
Jess
I agree with Brad here. Creating a mock object implies you are testing that type's public behavior. That is, you are specifically saying, "I need the public API of this object to behave in a certain way." This behavior is *independent* of however said API is implemented. This means you have an already-defined (though implicit) abstraction which needs to behave a certain way. In a static type system, this must be made explicit by creating an abstract type.
Sam Pearson
A: 

I like to use insults recycled from the Monkey Island games, e.g. "You fight like a dairy farmer!" Also, "Yo momma" jokes tend to work pretty well. If you're quick-witted, you can come up with your own insults.

Nathan Strong
nice... and yet no up vote from me
Michael Easter
wouldn't expect it; was just in the mood to be a smart-ass. ;)
Nathan Strong
-1; funny, but doesn't help the signal/noise ratio any.
Duncan Bayne
A: 

I generally take the route of creating a an interface and adaptor/proxy class to facilitate mocking of the sealed type. However, I've also experimented with skipping creation of the interface and making the proxy type non-sealed with virtual methods. This worked well when the proxy is really a natural base class that encapsulates and users part of the sealed class.

When dealing with code that required this adaptation, I got tired of performing the same actions to create the interface and proxy type so I implemented a library to automate the task.

The code is somewhat more sophisticated than the sample given in the article you reference, as it produces an assembly (instead of source code), allows for code generation to be performed on any type, and doesn't require as much configuration.

For more information, please refer to this page.

Steve Guidi
+2  A: 

I almost always avoid having dependencies on external classes deep within my code. Instead, I'd much rather use an adapter/bridge to talk to them. That way, I'm dealing with my semantics, and the pain of translating is isolated in one class.

It also makes it easier to switch my dependencies in the long run.

kyoryu
A: 

It is perfectly reasonable to mock a sealed class because many framework classes are sealed.

In my case I'm trying to mock .Net's MessageQueue class so that I can TDD my graceful exception handling logic.

If anyone has ideas on how to overcome Moq's error regarding "Invalid setup on a non-overridable member", please let me know.

code:

    [TestMethod]
    public void Test()
    {
        Queue<Message> messages = new Queue<Message>();
        Action<Message> sendDelegate = msg => messages.Enqueue(msg);
        Func<TimeSpan, MessageQueueTransaction, Message> receiveDelegate =
            (v1, v2) =>
            {
                throw new Exception("Test Exception to simulate a failed queue read.");
            };

        MessageQueue mockQueue = QueueMonitorHelper.MockQueue(sendDelegate, receiveDelegate).Object;
    }
    public static Mock<MessageQueue> MockQueue
                (Action<Message> sendDelegate, Func<TimeSpan, MessageQueueTransaction, Message> receiveDelegate)
    {
        Mock<MessageQueue> mockQueue = new Mock<MessageQueue>(MockBehavior.Strict);

        Expression<Action<MessageQueue>> sendMock = (msmq) => msmq.Send(It.IsAny<Message>()); //message => messages.Enqueue(message);
        mockQueue.Setup(sendMock).Callback<Message>(sendDelegate);

        Expression<Func<MessageQueue, Message>> receiveMock = (msmq) => msmq.Receive(It.IsAny<TimeSpan>(), It.IsAny<MessageQueueTransaction>());
        mockQueue.Setup(receiveMock).Returns<TimeSpan, MessageQueueTransaction>(receiveDelegate);

        return mockQueue;
    }
Adam Lenda
I have found a solution and posted here: http://www.dotnetmonkey.net/post/Hard-to-Moq.aspx
Adam Lenda
+1  A: 

I believe that Moles, from Microsoft Research, allows you to do that. From the Moles page:

Moles may be used to detour any .NET method, including non-virtual/static methods in sealed types.

Mathias