3

I am struggling to know how to decide what objects my test object interacts with should be mocked.

class MyClass {
  private Customer customer;
  private Invoice invoice;
  private PrintService ps;
  private DBAccessService da;
  private EmailService em;
  ..........
 }

I can see that the last 3 are to be mocked because they deal with some external systems. What about Customer and Invoice? If not, why?

  • One test strategy is to test lower level objects/layers first, then use those tested objects to test higher level layers. If that seems better to you (given your design and your requirements), then it could be the best strategy for you. You don't have to mock everything. – markspace Nov 14 '16 at 18:26
  • There is no complete consensus about this subject. And that's to put it mildly, there are bitter arguments about it. Whatever path you choose in the end, always remember what the purpose of automated testing is: to find errors in the shortest possible time with the smallest possible effort. Or to turn it around: to build up confidence about the correctness of your code. That's all that matters. – biziclop Nov 14 '16 at 18:27

1 Answers1

7

The general answer to the question "Should I mock all objects that my test object interacts with?" is a resounding no: that is not a rule you should internalize or follow. Mocks are one of many types of test double, and you'll have to use judgment about where to use mocks, where to use other fakes or test doubles, and where to use real collaborators. I do agree with your decision that the last three fields (services) are probably worth mocking, and if it were up to me, I would use real objects for the former two fields (Customer and Invoice).

Here, I would adhere to a guideline, don't mock data objects, which follows from a few observations:

  • Data objects are often extremely stateful, and mocking frameworks tend to stub state poorly. Mockito doesn't really have a great syntax for "getX returns 15 indefinitely, until you call setX(20), then getX returns 20". Thus, stubbing correctly is often hard.

  • For data objects that are just fields/getters/setters, there's not much value to verifying that couldn't be done by reading mutable state out of a real implementation. Who cares whether getY was called, as long as the value in the object was read? Who cares how many times setY was called, as long as the correct value ends up in the object? Thus, verifying is often unnecessary.

  • Data objects are usually written before the objects that consume them, so there's often a working implementation that already exists.

  • Data objects often have determistic behavior with few external interactions, so there's often little to be gained in improving test stability or reducing test flakiness.

As biziclop mentioned in the question comments,

always remember what the purpose of automated testing is: to find errors in the shortest possible time with the smallest possible effort. Or to turn it around: to build up confidence about the correctness of your code.

In this sense, mocking data objects has a high cost to the readability and correctness of your test, and is also unlikely to provide benefit regarding test correctness or stability. I'd avoid it.

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251