How can one gain confidence that what they’re testing works if one is using mocks?

I’m grappling with this now as I go through making changes in one of the services I’m working on. So much of the logic requires rework, which means the tests will need to change. And yes, the tests use mocks, meaning that the changes are significant.

But do they have to be? We’re effectively mocking things that can easily run as part of the test. Things like a DynamoDB store — which can run within a Docker container — or even services from other packages. Sure they’re not part of the “unit”, so using them in a unit test won’t make it a “unit test” anymore. But I’d argue that using “real” implementation of dependent systems would produce more confidence in the changes I’m making. I’m able to change the logic without changing much of the test itself. Surely this is worth the “unit test” purity price.

And even if the outcome is meant to change, that intention is made clear by simply changing that in the test, without touching any of the setup code. Nice and readable in the MR: the function was expected to do this, now it does that.

That said, I would concede that there’re legitimate cases for mocking. Namely, if it takes a significant amount of time to setup the dependencies, or you can setup the dependencies within the test itself, mocking is probably the best option. A slow test or, even worse, a test that won’t run if dependent services are unavailable, is worse than a bunch of mocks.

Maybe a good compromise is recognising that excessive mocking in a unit tests is a sign that a module has too many dependencies.