Dependency Pattern
We are using this pattern when creating a new Uber-FX dependency, it makes it easy adding new external dependencies later when your application evolves.
To explain this better, we will do this with a Notifier example.
Preparation
-
Define our
Notifierinterface:type Notifier interface{ Alert(ctx context.Context, msg string) } -
Create a dependency “container” for all future dependencies of the
Notifierimplementation and embedfx.Ininto it. This will mark it and will tellUber-FXto inject all the requested dependencies:// It's not public as you can see type notifierDeps struct { fx.In } -
Create an implementation struct:
// Notice again that's not public type notifier struct{ deps notifierDeps } -
Create a Constructor function that will return a
Notifierimplementation as a type:func CreateNotifier(deps notifierDeps) (Notifier,error) { return ¬ifier(deps:deps), nil } -
Finally, implement it:
func (n *notifier) Alert(ctx context.Context, msg string) { // alert someone }
Usage
Now, suppose you want to log every time you alert someone. All you need to do is:
-
Add a
log.Loggerdependency to thenotifierDepsstruct:type notifierDeps struct { fx.In Logger log.Logger } -
Use it:
func (n *notifier) Alert(ctx context.Context, msg string) { n.deps.Logger.WithField("msg", msg).Debug(ctx, "alerting") // alert someone }
Tests
You are happily using Notifier in your application, but what about tests?
You know, to test logic that has Notifier as a dependency. Notifier will probably call an external service, which is not available during tests.
One way to do it, is to use gomock.
-
You can add a comment above the
Notifierinterface://go:generate mockgen -source=notifier.go -destination=mock/notifier_mock.go type Notifier interface{ Alert(ctx context.Context, msg string) } -
Execute
go generate ./...and it will generate all the mocks in your application. -
Use the generated mock in your tests.
Remember not to call a real Notifier Constructor
Mortar includes mocks of all of its interfaces in their respective directories, for example a Logger mock.
You can find several test examples here.