Sometimes after choosing a package layout, the Go compiler complains that cyclical dependencies are not allowed.
We can override this in two ways: either using interfaces or using dependency injection. There is also a trick for using helper packages in unit tests.
Suppose you want to define two packages
b, and define
a.Foo() to call
b.Bar() to call
The portion of the cycle that can be imported separately (e.g. package
ain the example above) must pass its unit tests independently from the cycle. This implies that the package must define valid behavior even when the injection slots are not populated.
There is a substantiated argument that the interface-based approach described above is impossible or impractical.
Often we want to use a helper package in a unit test, but just in the unit test, and that import creates a dependency cycle.
For this, Go already has a native functionality: test files (
*_test.go) inside a package named
X can declare another package
X_test can import another package that then recursively depends on
X, and this way there is no cycle.
For example, in CockroachDB we often use
testserver in tests.
testserver depends on
pkg/server, which depends on
pkg/sql. So all the tests in the
server package that want a test server cannot be part of the
server packages; at the top of their source file we see
package sql_test and
Separately licensed packages inside CockroachDB: CCL and BSL