I'm penning this as I sometimes need a quick reference to give people on what "dependency injection" means.

This is most easily done through examples.

The problem

  • Imagine that we have some class that opens a client connection to the outside world (think a client for an API such as Twitter's)
  • Imagine that during testing, we might want to stop the method attempting to make an actual connection, for whatever reason
    • Maybe we're testing the connections separately during unit tests
    • Maybe we're running integration tests

How do you make sure that we don't create this connection? One way would be to switch on environment status, or something similar

def run(test=false):
    if not test:
        self.connection = create_connection

This approach is bad for a few reasons

  • It puts knowledge of testing environment and code into your production code, which couples your tests to your prod code (changing one could break the other)
  • It restricts the kind of testing that you can do

Inject instead!

def run(connection):
    self.connection = connection

Now, we can pass in whatever connection we like from our testing classes, and pass in the argument "one level up". The logic is the same, but the point where the parameter is created has shifted upwards.

  • Could pass a real connection to prod or local (read: docker) infra
  • Could pass in a mock object, or anything else (namedtuples/structs are useful here)

And that's it!