Your mock is taking the place of a collaborator. It's ideally doing one of two things:
- Providing information or data
- Doing a job
When the mock is providing information or data, it's enough that this should be a stub. You can set up the return value of the mock to the information required. This should be part of Arrange.
When the mock is doing a job, the delegation can be verified. This is why you have Assert.
What you're doing with the strict interaction is ensuring that every single interaction is expected, basically saying, "Here's what I expect to happen, and if anything else happens it's wrong." This is a different kind of testing to Act, Arrange, Assert, which says, "In this context, when I do this stuff, then I should get this outcome."
With a "nice" mock, you only need to worry about the interactions you're interested in. So, for instance, if I'm a controller and I'm looking up some information in one repository, validating it with a validator, then saving the result in another repository, I might have several tests:
- one to check that I'm validating against the right information
- one to check how I'm responding to incorrect validation
- and one to check that I save the item.
With the strict mock, you have to do all the expectations, even if all you're interested in is the "save". By using a nice mock, we can split up the different aspects of behavior and only focus on one of them in each test.
As an additional bonus, nice mocks allow you to do:
- Given a context
- When this event happens
- Then this outcome should occur
Whereas strict mocks make you do:
- Given a context
- Expect some stuff to happen
- When I perform an event
- Then go back and read what the outcome should have actually been.
The first of these is generally considered more readable.