Dependency injection supplies a component’s dependencies from outside instead of creating them internally. In Go, this decouples program logic from external inputs and outputs, making behavior easier to test without changing the program’s external behavior. section 5.0 section 5.2.1
A practical refactoring for a command-line tool follows these steps:
- Extract main’s core logic into a testable run function. section 5.3
- Group dependencies such as global inputs and outputs in an env struct. section 5.2.1
- Pass real dependencies from main and controlled fakes, such as in-memory buffers, from tests. section 5.2.1
- Update parsers and integrations to use the injected dependencies, then verify behavior manually and automatically. section 5.3 section 5.0
Injecting a logger into middleware
Middleware can accept a specific logger and return a handler-wrapping function instead of using a global logger. The logger is supplied when middleware is configured, which simplifies testing and preserves the func(Handler) Handler signature needed for composition. section 9.1.2 section 9.9
Figure 5.2 Moving main's code into a run function that accepts an *env struct. The env struct has fields for us to inject the global variables, such as the os.Stdout. This approach allows main to inject real globals to run, and tests can inject controlled fakes that we can observe from tests later.
The diagram shows main passing real globals through an env struct to run while tests pass controlled fakes that can be observed. section 5.2.1




















