22

My class has a dependency which I mocked in my unit tests. I was getting a null reference exception in a place where it didn't make much sense to me.

I just realised it was because I didn't set up my mocked dependency. This dependency is tested but it doesn't connect to anything like file system or data sources.

I only wanted to test my new code in this new class but I guess in this case it is better not to mock at all.

Is this conclusion correct?

Dave Schweisguth
  • 36,475
  • 10
  • 98
  • 121
Fabio Milheiro
  • 8,100
  • 17
  • 57
  • 96

3 Answers3

28

Correct. You should mock things that depend on anything persistent or external in order to prevent the test from depending on anything persistent or external.

If the dependency does not depend on anything persistent or external, the only benefit you gain from mocking it is that the test will work properly even if the dependency is wrong - but that's assuming the mock works properly. For that you need to either:

  1. Write a mock that emulates the dependency completely.

  2. Write a mock that emulates the dependency for the specific cases that will be used in the test.

The first option is outright ridiculous - why should your mock be any better than the original dependency? After all, it's safe to assume much more effort was invested in the original dependency than in the mock...

The second option means your mock knows the exact details of the implementation - otherwise you won't know how the implementation uses the dependency so you don't know how to mock those specific uses. This means the test does not serve one of the main purposes of unit tests - verifying that the code works properly after changes to the implementation.

The drawbacks of mocking are too big and the advantages are too small - especially considering that you can always run the dependency's tests to check if it works properly...

Idan Arye
  • 12,402
  • 5
  • 49
  • 68
  • 4
    I respectfully disagree. I think there's a better answer for this: https://stackoverflow.com/questions/38181/when-should-i-mock – vpassapera Jan 21 '17 at 12:51
  • Can you define what you mean by "persistent" and "external"? – B T Aug 23 '18 at 00:02
  • 4
    "Persistent" means it existed before the test and will stay there after the test - with all the changes done to it during the test remaining. This can be a problem because you need to make sure it's state is correct before the test, and need to leave it in a stable state after the test (for other things that want to use it) "External" means it affects things outside the test - things you usually don't want to affect. – Idan Arye Aug 29 '18 at 16:48
14

It sounds like it's working in your case, but it's not true in general that the only reason to stub or mock is to get external data sources and such out of your test's hair. Other reasons include

  • a method might be slow all by itself
  • it may be difficult to come up with the right parameters to pass to another class's method to get it to return the value that you need for a test of your method
  • the method you're testing needs an instance of another class which changes a lot, and you don't want your tests of the caller to break when the callee changes
  • the method you depend on is complicated enough to need its own tests, fully testing your method without stubbing or mocking means fully testing the methods that it calls (within your method's own tests), and this results in duplication between tests of your class and tests of the methods it calls
  • you're doing TDD from the outside in and you haven't written the callee yet, just designed its interface!
Dave Schweisguth
  • 36,475
  • 10
  • 98
  • 121
  • 1
    The 4th item (dependency is complicated) doesn't sound like necessarily a good candidate for mocking. Regardless of mocking or other unit tests, you should still exercise your code unit fully. If your code-unit's dependency needs its own tests, so be it - its often a good idea to have unit tests for private dependencies. – B T Aug 23 '18 at 00:01
  • I think we're mostly agreeing at length here. But the heart of reason 4 is that when tests of a method and tests of a method it calls have duplication due to the lower-level method, mocking is a way to address that duplication. – Dave Schweisguth Aug 23 '18 at 15:09
  • 1
    Ah, I think I see what you're saying. You're saying in cases where you're doing something like testing if `a(x)` contains a large object returned by `b(x)`, testing to make sure that large object has all the right properties in both the test for `a` and for `b` is needlessly redundant. I can get behind that. – B T Aug 23 '18 at 23:13
  • 1
    Exactly. A related case is where `b` needs complicated mocking; doing that mocking in both `a` and `b` would be duplicative, which you could solve by mocking `b` in tests of `a`. – Dave Schweisguth Aug 24 '18 at 02:14
  • 1
    The points you raise are valid, but there is still danger in mocking. In particular, in cases 2/3, there is usually a complex interaction between the method under test and the dependency or paramter class - mocking that class means not testing the interaction, which risks hiding bugs. If the interaction is so complex that it is hard to test, I'd rather refactor the code than hide the problem with mocks... – sleske Apr 15 '20 at 11:26
  • For some reason, even though this answer is detailed, I smell bull here. It's not a good answer, simply because it misunderstand what is a unit test. – windmaomao Feb 14 '23 at 18:17
4

It depends: can you consider the dependency to actually just be a private implementation detail? If so, then mocking it only makes your test more brittle.

However, if it's a dependency that is actually injected into your SUT, then it absolutely should be replaced with a test double in your unit test.

The SUT should be the only interesting thing in your test. Everything else should be rote, boring, and constant, in order to ensure your SUT is operating in optimal conditions (for the scenario being tested).

Lilshieste
  • 2,744
  • 14
  • 20