6

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
    FYI: The generic term is "test double" – Vaughn Cato Oct 18 '16 at 2:06
2

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.)

  • 7
    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. – Callum Bradbury Oct 17 '16 at 13:28
  • 3
    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. – Karl Bielefeldt Oct 17 '16 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. – Phuong Nguyen Oct 18 '16 at 1:38
  • 2
    @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 – Phuong Nguyen Oct 18 '16 at 1:41
  • @KarlBielefeldt If your code is organised well enough, your tests shouldn't be mock-heavy, and if they are it's a sign you should probably add a layer of abstraction somewhere between what you're mocking out and what you're testing, in my opinion. Mocks are chosen because they're easy to configure to test various different behaviours from code outside your control (from a class perspective), and using actual implementations can make configuring your unit tests far more complex then they have any right to be. They're not meant to be magic, error free fix-alls, but they are meant to be used. – Callum Bradbury Oct 18 '16 at 9:13
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.

  • 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 – Phuong Nguyen Oct 18 '16 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 Oct 18 '16 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. – Callum Bradbury Oct 18 '16 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. – Matthew Flynn Oct 18 '16 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.

  • 3
    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. – Robert Harvey Oct 19 '16 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 Oct 21 '16 at 6:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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