Interface With Your Database in Go Tests

Caleb Hearth

Go’s strong type system includes a concept called interface. In Go, an interface is a collection of function signatures. Any type that implements all of those functions is implicitly able to be used as an interface type.

For example, Go’s empty interface, interface{}, is similar to Ruby’s BasicObject or Java’s Object, from which all classes inherit in these languages.

More concretely, Ruby’s Comparable requires a #<=> method to be defined. To represent that in Go, we might define these interfaces as:

type Comparable interface {
  // Compare accepts another Comparable of the same type and returns an int
  // value representing whether the other is less than (-1), greater than (1),
  // or equal to (0) the callee.
  // Compare returns an error if the Comparable argument is of a different type
  // than the callee and cannot be compared.
  Compare(Comparable) (int, error)

We could then use any type that implemented Comparable in methods defined to operate on Comparable:

func (self int) Compare(other Comparable) (int, error) {
  switch other.(type) {
  case int:
  case float64:
    other = int(other)
  case string:
    other, err = strconv.Atoi(other)
    if err != nil {
      return 0, err
    return 0, fmt.Errorf("%v is not comparable to type int.")

  if other > self {
    return 1, nil
  } else if other == self {
    return 0, nil
  } else {
    return -1, nil

func Equal(first, second Comparable) (bool, err) {
  if result, err := first.Compare(second); err != nil {
    return false, err

  return result == 0, nil

Okay, that’s out of the way. Now let’s look at how we can use interfaces to abstract away a database in tests.

We’ll define a DataAccessLayer interface which includes signatures for the methods we’ll need:

type DataAccessLayer interface {
  FindAuthor(int) Author
  FindPostsForAuthor(Author) []Post
  FindCommentsForPost(Post) []Comment

Building to that interface, we’d define a type postgres that included code to retreive each object or collection from a database connection it maintains internally.

But for our unit tests, we don’t want to ever touch the database. By the power of interface, we can define a dummy TestDAL that returns known values so that we can test DataAccessLayer‘s collaborators in relative isolation.

type TestDAL {
  Author   Author
  Posts    []Post
  Comments []Comment

func (t *TestDAL) FindAuthor(int) Author {
  return t.Author

func (t *TestDAL) FindPostsForAuthor(Author) []Post {
  return t.Posts

func (t *TestDAL) FindCommentsForPost(Post) []Comment {
  return t.Comments

We ignore the arguments because we initialize the TestDAL with the result we want, so they’re not needed.

In our test, we can create just the amount of data we need:

func TestDALCollaborator(t *testing.T) {
  dal := TestDAL{Author: Author{}}
  collaborator := Collaborator{DAL: dal}

  result := collaborator.FunctionNeedingAnAuthor()

  // Some verification

And we never need to hit an external dependency like the Postgres database in our test, keeping it blazing fast.