views:

666

answers:

7

I recently discussed with a colleague about mocking. He said that mocking classes is very bad and should not be done, only in few cases.

He says that only interfaces should be mocked, otherwise it's an architecture fault.

I wonder why this statement (I fully trust him) is so correct? I don't know it and would like to be convinced.

Did I miss the point of mocking (yes, I read Martin Fowler's article)

+1  A: 

Edit: Since you have clarified that your colleague meant mock class is bad but mock interface is not, the answer below is outdated. You should refer to this answer.

I am talking about mock and stub as defined by Martin Fowler, and I assume that's what your colleague meant, too.

Mocking is bad because it can lead to overspecification of tests. Use stub if possible and avoid mock.

Here's the diff between mock and stub (from the above article):

We can then use state verification on the stub like this.

class OrderStateTester...
  public void testOrderSendsMailIfUnfilled() {
    Order order = new Order(TALISKER, 51);
    MailServiceStub mailer = new MailServiceStub();
    order.setMailer(mailer);
    order.fill(warehouse);
    assertEquals(1, mailer.numberSent());
  }

Of course this is a very simple test - only that a message has been sent. We've not tested it was send to the right person, or with the right contents, but it will do to illustrate the point.

Using mocks this test would look quite different.

class OrderInteractionTester...
  public void testOrderSendsMailIfUnfilled() {
    Order order = new Order(TALISKER, 51);
    Mock warehouse = mock(Warehouse.class);
    Mock mailer = mock(MailService.class);
    order.setMailer((MailService) mailer.proxy());

    mailer.expects(once()).method("send");
    warehouse.expects(once()).method("hasInventory")
      .withAnyArguments()
      .will(returnValue(false));

    order.fill((Warehouse) warehouse.proxy());
  }
}

In order to use state verification on the stub, I need to make some extra methods on the >stub to help with verification. As a result the stub implements MailService but adds extra >test methods.

Ngu Soon Hui
+15  A: 

Mocking is used for protocol testing - it tests how you'll use an API, and how you'll react when the API reacts accordingly.

Ideally (in many cases at least), that API should be specified as an interface rather than a class - an interface defines a protocol, a class defines at least part of an implementation.

On a practical note, mocking frameworks tend to have limitations around mocking classes.

In my experience, mocking is somewhat overused - often you're not really interested in the exact interaction, you really want a stub... but mocking framework can be used to create stubs, and you fall into the trap of creating brittle tests by mocking instead of stubbing. It's a hard balance to get right though.

Jon Skeet
I wonder if the OP's friend might have conflated several meanings of "interface". He may have read something about mocking class interfaces and thought it meant the thing referred to by the "interface" keyword in his language of choice.
Ewan Todd
+1 Besides the fact that it makes sense that dependencies you want to mock also are called by an interface, there are technical reasons to not mock classes. See my answer.
Stefan Steinegger
Ewan: I refer to the class interface.
furtelwart
Every class has an implicit interface, which is the set of public methods and constructors it defines. There is nothing wrong in seeing this as the "protocol" of the class. So, "protocol testing" does not imply that classes should not be mocked.Also, creating a mock does not mean that each and every mocked method must be explicitly specified in the test. Expectations can be either strict or non-strict, where the non-strict ones are freely allowed to occur any number of times in the code under test. In other words, a stub is just a type of mock where all expectations are non-strict by default.
Rogerio
@Rogerio: I still find it simpler to specify APIs via interfaces, as it means you don't get "incidentally public" methods (e.g. those used to implement *other* interfaces) as part of the dependency mix. When you start only mocking *some* of the methods, using production code for others, that ends up as an uncomfortable mixture IMO - because it means you're assuming that the bits you're mocking aren't affected by the bits you're not and vice versa... and don't forget that this *isn't* the class under test we're talking about.
Jon Skeet
Yes, IF your classes implement multiple separate interfaces/abstractions. Most classes, though, have no such need. For them, the public interface of the class is the only interface that counts; and through proper design you can avoid exposing too much as public members.
Rogerio
+3  A: 

Generally you'd want to mock an interface.

While it is possible to mock a regular class, it tends to influence your class design too much for testability. Concerns like accessibility, whether or not a method is virtual, etc. will all be determined by the ability to mock the class, rather than true OO concerns.

There is one faking library called TypeMock Isolator that allows you to get around these limitations (have cake, eat cake) but it's pretty expensive. Better to design for testability.

Anderson Imes
As no language has been defined I'll just point out the Java equivalent - EasyMock can mock classes. But it has its issues. http://easymock.org/EasyMock2_4_ClassExtension_Documentation.html
mlk
For Java, there is the JMockit toolkit, which is free and open source.It's equivalent to TypeMock, to the best of my knowledge.(BTW, anybody knows if TypeMock supports on-demand mocking of implementations?)
Rogerio
A: 

The answer, like most questions about practices, is "it depends".

Overuse of mocks can lead to tests that don't really test anything. It can also lead to tests which are virtual re-implementations of the code under test, tightly bound to a specific implementation.

On the other hand, judicious use of mocks and stubs can lead to unit tests which are neatly isolated and test one thing and one thing alone - which is a good thing.

It's all about moderation.

Avdi
I don't think you got my question right.
furtelwart
You asked why mocks are bad. I explained how they can be both bad and good. If you were expecting people to just confirm your colleague's bias then I'm sorry. Otherwise, I don't see how I misunderstood your question.
Avdi
Ah, now I see that you are refering to some Java (or C#?)-specific distinction between classes and interfaces. You should tag your questions with "java" or "C#" if you are talking about language-specific stuff. Many (most) other OO languages have no such distinction between classes and interfaces.
Avdi
Ah... you are a Ruby guy :)
Anderson Imes
At one time or another I have been a REXX, C, C++, 68k ASM, C#, Java, Perl, TCL, Python, Haskell, Lisp, and Ruby guy.Of that list, only two have a concept of interfaces.
Avdi
Oh yeah, forgot Javascript and VB. Can't remember if VB had interfaces; considering it never met a language feature it didn't like, it probably did.
Avdi
+9  A: 

IMHO, what your colleague means is that you should program to an interface, not an implementation. If you find yourself mocking classes too often, it's a sign you broke the previous principle when designing your architecture.

Pascal Thivent
+1, surely this is what the colleague was talking about.
Jeff Sternal
"Program to an interface..." only means you declare fields, variables, parameters and return types with the abstract type instead of the concrete implementation type. Nothing more. Therefore, for a class that does not implement a separate abstract type, mocking it (when needed in a test) would be perfectly fine. Creating a pointless separate interface for such a class would only be a waste of effort.
Rogerio
@Rogerio: I also relate to the comments you wrote on my answer. I think that you didn't really understand what interfaces are good for. The don't have much to do with abstract classes. From my experience, the more I'm using interfaces, the more I see its benefits, although I have to write more code, have more indirections and need dependency injection and stuff like this.
Stefan Steinegger
I did not specificaly mention abstract classes, only "abstractions" and "abstract types". A Java interface IS an abstract type.I understand abstractions just fine. I suspect, though, that perhaps you are confused by what "coupling" really is (and maybe "cohesion" as well). Writing extra code with no clear business or technical justification is just wrong. I have seen it enough to know how painful working on such a codebase can be.
Rogerio
+5  A: 

Mocking classes (in contrast to mocking interfaces) is bad because the mock still has a real class in the background, it is inherited from, and it is possible that real implementation is executed during the test.

When you mock (or stub or whatever) an interface, there is no risk of having code executed you actually wanted to mock.

Mocking classes also forces you to make everything, that could possibly be mocked, to be virtual, which is very intrusive and could lead to bad class design.

If you want to decouple classes, they should not know each other, this is the reason why it makes sense to mock (or stub or whatever) one of them. So implementing against interfaces is recommended anyway, but this is mentioned here by others enough.

Stefan Steinegger
You are really talking about the limitations of certain mocking tools, not about something that is inherent to the mocking of reference types (classes, interfaces, enums, and annotations, in the Java language). When mocking a class, it's not necessary to create a subclass.With the JMockit tool, for example, mocking a class or an interface is practically the same (even if the class is final/sealed, or abstract).
Rogerio
@Rogerio: May be it's specific to certain mock tools. If these limitations aren't there an mocking classes is "practically the same", then there is no technical disadvantage. The last paragraph sill applies, decoupling classes means running them in isolation must be possible, mocking becomes natural, interfaces as well. Not decoupling classes means bad class design.
Stefan Steinegger
"Decoupling classes" by simply introducing a separate interface for the depended one, when that interface will never have a second implementation, is the true case of bad design. To separate abstraction from implementation is only justified when the benefits are clear and obvious; to do so otherwise is over-engineering, which can (and does) bring huge harm to real software projects.
Rogerio
@Rogerio: I agree that using interfaces for every dependency is overkill and that there needs to be a benefit at the end (for everything we do). But the "only one implementation" is not an argument at all. It's not important how many implementations there are, but only if one class needs to know the other. Using interfaces you can easily limit the dependency of one part of the system to the other. This is benefit enough. Look at Jon Skeets answer, paragraph 2, if you don't believe me.
Stefan Steinegger
I also responded to Jon.I assume you refer to something like the "Separated Interface" pattern, right? (Where you define a separate interface in the same package of the dependent class and then rely on some external mechanism to obtain the implementation instance.) It is valid, of course, but only if the direct coupling between packages would be undesirable. In most cases, though, direct coupling is the best option; after all, short of messaging, "data coupling" is the weakest form of coupling: see http://en.wikipedia.org/wiki/Coupling_(computer_science).
Rogerio
@Rogerio: We are most probably talking about the same thing, but in a different environment. An example from the project I'm working on: there are many services, framework services and domain services. They are exclusively called by interfaces. There is no service knowing the other directly. Even if they are in the same assembly and there is only one (real) implementation. There are services implementing more then one of these interfaces, because every interface is designed for a certain kind of dependency and should to be as small as possible, to avoid higher coupling the necessary.
Stefan Steinegger
Yes, what you describe is very different from what I am used to.In the projects where I was a developer, a class being coupled to the public interface of another was no big deal. Those interfaces were only as big as they had to be. Maybe it's a difference between having many separate classes with cohesive interfaces, or having many separate interfaces which are implemented by bigger, less cohesive classes. I prefer the former approach.
Rogerio
A: 

It makes sense to mock classes so tests can be written early in the development lifecycle.

There is a tendency to continue to use mock classes even when concrete implementations become available. There is also the tendency to develop against mock classes (and stubs) necessary early in a project when some parts of the system have not been built.

Once a piece of the system has been built it is necessary to test against it and continue to test against it (for regression). In this case starting with mocks is good but they should be discarded in favour of the implementation as soon as possible. I have seen projects struggle because different teams continue to develop against the behaviour of the mock rather than the implementation (once it is available).

By testing against mocks you are assuming that the mock is characteristic of the system. Often this involves guessing what the mocked component will do. If you have a specification of the system you are mocking then you don't have to guess, but often the 'as-built' system doesn't match the original specification due to practical considerations discovered during construction. Agile development projects assume this will always happen.

You then develop code that works with the mock. When it turns out that the mock does not truly represent the behaviour of the real as-built system (eg. latency issues not seen in the mock, resource and efficiency issues not seen in the mock, concurrency issues, performance issues etc) you then have a bunch of worthless mocking tests you must now maintain.

I consider the use of mocks to be valuable at the start of development but these mocks should not contribute to project coverage. It is best later if the mocks are removed and proper integration tests are created to replace them otherwise your system will not be getting tested for the variety of conditions which your mock did not simulate (or simulates incorrectly relative to the real system).

So, the question is whether or not to use mocks, it is a matter of when to use them and when to remove them.

Moa