9

Just for the sake of discussion below, when I refer to mocking, I mean mocking/stubbing/faking, as contrast to use real implementation in testing

I just had some discussion with my colleague during a pair programming session regarding whether we should use mocking in unit tests for our own written code. (Not sure whether this matters, but we are pair programming on a Ruby/Rails code base)

His argument is that we should not use mocking if it's our own written code. Mocking should be used only to stuffs out external dependencies (.e.g. third party system). Let's say if there are class A and B, and A depends on B (.e.g. one of A's method creates and uses B), he said we should not mock B out when testing A (both A and B are written and maintained by us), since B is internal implementation details of A.

While I agree with him to some degree, I still find some cases where mocking our own code is necessary and required:

  • First, I believe if we don't mock dependencies of a class, it's no longer unit test. So like above example, we are writing integration test for class A and B. I'm not saying integration tests are not needed, but there are some disadvantages of it compared to unit test, .e.g. run slower and when a test fails, you need to trace the implementation code to identify the components that cause the failure. And therefore we should make it clear what's unit test, what's integration test
  • Second, we should not test and care about implementation details of a class as long as its public contract still maintains. However, I believe we should test a class's interaction with its (peer?)dependencies since those interactions are expected behaviors of that class. In some cases, it's not easy to determine what is implementation details and what is dependency, .e.g. in a layered application (controller -> application service -> domain), is an application service dependency or internal implementation of a controller?

So my questions are:

  • What are your opinions on when and where to use mocking?
  • Any good heuristics to decide what is dependency and what is internal implementation details? Take for example the layered application above

Not sure whether it's because my background is in C#, I find it difficult to accept the idea of mocking is not needed when testing our own code

1
  • 3
    FYI: The generic term is "test double" Commented Oct 18, 2016 at 2:06

3 Answers 3

3

His argument is that we should not use mocking if it's our own written code. Mocking should be used only to stuffs out external dependencies (.e.g. third party system)

Mocking should only be used if absolutely necessary as every mock means you are testing how a piece of code behaves when connected to that mock, rather than the real code.

See Stop using mocks, along siwth Mock yourself, not your tests and many more easily searched-for articles on why mocking should be avoided.

Let's say if there are class A and B, and A depends on B (.e.g. one of A's method creates and uses B)

Is B a public class? If so, A shouldn't be creating an instance of B; that's tight coupling. Instead, A should be passed an instance of the interface IB, or IBFactory from which it can request an IB instance. If B is well behaved with deterministic behaviour and no external side effects, then it can even be used directly when testing A.

First, I believe if we don't mock dependencies of a class, it's no longer unit test.

Sorry but that is nonsense. A unit test is a test of a unit of code that can be run in parallel with other tests without affecting those tests and without external side effects. That unit of code could be a function, a collection of functions (eg a class), or nearly the whole system, just so long as it doesn't have side effects or affect other tests.

What are your opinions on when and where to use mocking?

You use mocking only when it can't be avoided.

Any good heuristics to decide what is dependency and what is internal implementation details?

Is the dependency public? If so, then it is not an implementation detail. If it isn't public, then it is indeed an implementation detail, but is also a dependency (and if it's an implementation detail it absolutely should not be mocked as tests shouldn't go anywhere near implementation details.)

11
  • 8
    I believe the point of mocking dependencies is to ensure that if the test fails, only the subject of the test could be the cause for the failure. If you're testing class A and using a real instance of B instead of mocking IB, if B has a bug in it, your A tests will fail. That's why I mock everything, until you reach integration tests, where you want to test all your functionality together. Commented Oct 17, 2016 at 13:28
  • 4
    There's only one problem with that argument, @Callum. When you're writing mock-heavy unit tests and they fail, what's the first thing you suspect? You blame the mock first, then the UUT. Having multiple causes of failure is unavoidable. Mocks aren't chosen because they are magically error-free. They are chosen because they break the dependency chain, are easier to introspect, and sometimes execute faster. Commented Oct 17, 2016 at 17:53
  • @David thanks for your answer. In response to your answer, I have updated my question to be more clear. When I said mocking, I meant all kinds of mocking/stubbing, as compared to using real implementation. Commented Oct 18, 2016 at 1:38
  • 4
    @David I have read the 2 links mentioned in your answer: the first article, actually is actually pointing to another article which is the current approach that I'm using (docs.google.com/file/d/0B_zwMmx15DL8NDdVT2gxLWk1OHc/edit?pli=1). In the second article, the author admits he used integration test to avoid using mock. That leads me back to your conclusion on definition of unit test. To me, a unit test should test smallest possible unit of code, which in a OO project, is normally a method or a class. A unit test that tests nearly the whole system is beyond my imagination Commented Oct 18, 2016 at 1:41
  • 1
    @DavidArno The point of unit tests is to test an individual piece of code, if there's a bug in B your unit tests for B should find them. If there's a bug in B and your tests in A find them, that's going to cause confusion and false negatives. The key to unit tests is that they test very specific things, and are free from outside influences, if you allow A to use B in tests you're muddying the waters, it's better to have individual tests for each class, so that you can easily identify the reason for failure, and come up with a solution. Commented Oct 19, 2016 at 11:15
1

There's three good arguments for using Mocks (and by mocks, I mean those items created by a framework like Mocha that allows you to assert whether the mock has been called):

  • It is important to know that the object under test correctly and consistently calls the other object in a specific manner and/or a specific number of times.
  • It is important to prevent the side effects that may be caused by calling other object methods.
  • It is important to isolate the unit of code you want to test in order to pinpoint the cause of failures, much as @Callum points out in his comment on the David Arno's answer.

If you don't care about these items, Mocks aren't really necessary.

4
  • I have updated my question to be clearer. Your first point is actually what I want to ask: some people might say testing that the class is calling the other object specific number of times might be going too much into internal implementation details of original class. So how do you differentiate what is implementation details and what is dependency that needs testing Commented Oct 18, 2016 at 1:50
  • 2
    I'd add the case where you want to ensure the tested code can handle cases that are hard or complex to induce without mocking. For example; How does my class handle an out of memory exception thrown by its dependency without actually forcing the dependency to run out of memory?
    – axl
    Commented Oct 18, 2016 at 4:58
  • 1
    @axl Exactly, it's about having 100% control over the dependencies being passed in, and what they're outputting, without having to mess up your tests with setup / configuration / manipulation code required for using concrete instances. Commented Oct 18, 2016 at 9:21
  • @PhuongNguyen : A unit test is there to ensure the unit of code is behaving the way it is supposed to. The number of calls to another object may be important. For example, you may have built a function that is calling an IO component that you've also built, and you'd like to know that the function does so optimally. Then again, it may not be important to know how often the method calls some transformational helper function. It's a judgement call you have to make on a case by case basis. Commented Oct 18, 2016 at 16:11
1

C# background here as well. You may want to look up 'mockist' (aka London) approach to TDD (as opposed to classical/Detroit one). I personally have used it with great success in many commercial projects, and found it to be the best way to test my units in perfect isolation. You end up with amazingly decoupled design that way.

Don't listen to people who tell you to rely on integration tests. Integration tests are a scam, because there is no way in hell you'll be able to cover all combinations of edge cases inside the chain of units that your integration test is supposedly testing. Focus on having perfectly tested units, and the whole system will just work when you compose your object graph (I usually throw in a couple integration tests as a sanity check).

I highly recommend the following book, especially the first few chapters that explains the mockist approach to TDD perfectly: Growing Object-Oriented Software, Guided by Tests

As far as your question regarding what to mock? I mock anything that's not under the test. Usually it means mocking the interfaces of the dependencies that are being injected into the constructor of the class that's being unit tested. With C# we have the advantage of having access to Moq, which is not only very powerful, but also very concise and readable.

2
  • 5
    Cool. So far, we've had one answer that says, in effect, "Don't write unit tests" (or at least ones that require mocks, which pretty much limits you to writing pure functions), and another answer (this one) that says "don't write integrations tests." Looks like I don't need to write tests at all anymore. Thanks! You guys have saved me a lot of work. Commented Oct 19, 2016 at 2:15
  • I strongly disagree that integration tests are as useless as you seem to imply. Unit and integration tests are testing different aspects. I can have 100% coverage on my units and still have an application that does absolutely nothing right. They most definitely complement each other. Some label their integration tests "QA-staff" and "users" but that's a different problem. :)
    – axl
    Commented Oct 21, 2016 at 6:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.