Published on

Testing in Go Using Dependency Injection with Code Examples

Authors
  • avatar
    Name
    Razvan
    Twitter

Dependency Injection is a design pattern that aims to separate the creation of objects from their use. It promotes loose coupling between components, making it easier to manage dependencies and test code. In Go, Dependency Injection can be implemented using interfaces and function parameters.

Let's start by creating a simple example to demonstrate Dependency Injection in action.

Defining the Interface and Implementation

First, let's define a simple interface, Greeter, and its implementation, Person:

package main

// Greeter describe the methods necessary to implement the Greeter interface
type Greeter interface {
    Greet(name string) string
}

// Person implements Greeter
type Person struct{}

func (p Person) Greet(name string) string {
    return "Hello, " + name
}

Dependency Injection

Now, let's create a function, GreetPerson, that depends on the Greeter interface. This function accepts a Greeter interface and a name as parameters and uses the Greeter to generate a greeting message:

// GreetPerson produces a greet
func GreetPerson(g Greeter, name string) string {
    return g.Greet(name)
}

❗️Pay attention to the first parameter of the GreetPerson function. It takes in a Greeter, not an implementation like Person. Person would still work, but you won't be able to use Dependency Injection for tests.

Testing with Dependency Injection

To test the GreetPerson function, we can create a mock implementation of the Greeter interface and pass it to the function. This allows us to isolate the behavior of the GreetPerson function and test it independently of the Person implementation:

type MockGreeter struct{}

func (m MockGreeter) Greet(name string) string {
    return "Mocked greeting, " + name
}

func TestGreetPerson(t *testing.T) {
    mockGreeter := MockGreeter{}
    result := GreetPerson(mockGreeter, "Alice")

    expected := "Mocked greeting, Alice"
    if result != expected {
        t.Errorf("Expected '%s', got '%s'", expected, result)
    }
}

Dependency Injection is a powerful technique for writing testable and maintainable code in Go. By decoupling components and using interfaces, it allows developers to isolate the behavior of individual functions and test them independently. This approach can lead to more robust and reliable code, making it an essential technique for any Go developer to master.