If it's a feature or integration test, why is it a problem to pull in the other packages?
If it's a unit test, why not mock out the other dependencies to focus on the narrow behaviour?
Go makes the latter both easier (implicit interface typing) and harder (lots of libraries only providing physical structs).
I have to admit I've grown nervous about tests that require you to crack open an object to inspect its internal state. I've often seen designs that "need" private variable inspection recomposed into a more functional style or broken into smaller, cooperating modules/objects.
Put another way: if the module's behaviour is so complex that you must inspect private state to assure behaviour, perhaps the module is too complex overall.
Of course YMMV, consult a doctor etc etc
> If it's a feature or integration test, why is it a problem to pull in the other packages?
The compiler does not allow the cyclic dependency (even if it's only caused by testing code).
And to pick a nit, to me, if there are several units of your system pulled in, it's arguably not a unit test. It's an integration test.
I don't love mocks, but I don't hate them either. They have their place as part of an overall testing pyramid.
To me, mocks are useful for one thing only: there is some expensive or flaky dependency of your code that you may have poor visibility into, and you want to write a test that does not rely on its availability. Mocks for databases, file systems, REST APIs, externally maintained libraries, etc. all make sense to me. But if some library is developed locally (or in the extreme case, by you) and you can easily depend on its existence and stability, then I see no reason not to write code that depends on that library and test against that library. This is a testing strategy for a pragmatist, not a purist.
Go in particular makes it easy to separate a single codebase into separate logical packages, and if you do so, it often makes sense to test them together. That's why this is a pretty Go-specific issue.
That said, to play devil's argument, why not just make all implementation details public? I will say I remember being pissed off by Go packages that don't publicize all of their types and interfaces, which made writing tests against their behavior (usually requiring mocking, hence the need for the publicized types/interfaces) to be painful/impossible.
Making everything public runs the risk of other modules using internal implementation details, and that entanglement makes changing things a lot harder.
For a small project where you can easily control this, it's likely not an issue. But we are big enough that no one person knows all the code changes that are going on in all modules.
Exported vs non exported also serves as implicit documentation, it makes understanding things easier when you can tell right away what is internal and what is not.