func newMocks(
) (
foo Foo, bar Bar, baz Baz,
cleanup func(),
)
and making the caller responsible for calling the cleanup function, possibly in a defer. To me, this seems like a good trade off between making a little more work for the caller and keeping things explicit and under the caller's control.
This doesn't work with the third example, ie where the set of mocks is not the same for every test. This suggestion devolves to the original code that we were trying to refactor.
Then the original code is perfectly fine and does not need refactoring. You create the mocks you need with cleanup defers and you're done.
You could just make a function that creates all the mocks needed for all tests, but you don't like that. So the only option left is to specify which mocks you need for each test... which is exactly what the original code is doing.
You're running into a wall because you're trying to abstract code that's already maximally abstracted.