But even here you’re testing the same code twice. One directly with the tests for the class the static methods live in and once accidentally when you test the class that includes the util class as a dependency. This situation can be fixed by replacing the static methods with Functions.
Because you have to address the separate permutations and concerns of multiple stack levels versus just declaring what you want the result to be from those additional stack levels. In essence, your "unit" test is a lie because your testing other units accidentally. I see a similar problems a lot with classes that have a small number of public methods which delegate to a larger stack of internal private calls. Unit tests are about testing the unit explicitly and forcing/contriving results of dependencies which you shouldn't be concerned with because those dependencies have been explicitly tested elsewhere. When these situations arise what you have are in memory integration tests, not unit tests.
As an example, suppose I have a static method that takes in an object and returns a result based on the state of that object. Now I have conditional logic in the unit under test that has a dependency on the result of that static method. In my unit test, I don't want to go to the trouble of creating the state of the object to force the delegate call to return a certain result that determines the execution flow, I want to just force that call to return the result I need.
This is an extremely bad habit, people over use it to make testing easier by mocking all over the place. They end up writing tests that are coupled to the implementation, and any small change breaks them.
Please go through the trouble to create the state of your object that you want to test, don't just mock other dependencies, which dependencies your method uses or how it does it's job is no concern of the test at all.
I agree, mocks should not be used and if you remove mock dependencies it usually exposes glaring problems in the code organization and design because the tests become overly complex. The dependencies should be coded to an interface so that you can inject whatever implementation you want.
> I don't want to go to the trouble of creating the state of the object to force the delegate call to return a certain result that determines the execution flow, I want to just force that call to return the result I need.
It certainly sounds like your stateful object is too complex. Simplify your state.