I think your intuition is getting there. Using DI always is an anti-pattern[0]. DI in general should only be used to nasty, circular-esque problems. If you can split your code between pure and impure code, and then just pass around the data, you mostly don't need it at all. Passing functions around is more complex than passive data, so you need a really good reason to do so.
The GP asked how to do mocking, and my answer is: Don't mock. Unit test pure code. Integration test impure code.
You're right. I don't actually DI always. Only (most of the time) when I have may have multiple implementations of a function, mock the function, or test it with different implementations of its depenencies.
The GP asked how to do mocking, and my answer is: Don't mock. Unit test pure code. Integration test impure code.
[0]: https://blog.ploeh.dk/2017/01/27/from-dependency-injection-t...