Skip to Content
โ†All posts

Testing unexported identifiers in Go

In order to minimise the surface area for testing a common practice is to focus testing only on the public API of a package, placing all the tests is a _test package.

For example, consider a simple math package with an exported function Square.

square.go
package math

func Square(a int) int {
  return a * a
}

Tests for this might look like so...

square_test.go
package math_test

import (
  "testing"

  "path.to/math"
)

func TestSquare(t *testing.T) {
    if result := Square(2); result != 4 {
      t.Errorf("Exected Square(2) to equal 4 but got %d",  result)
    }
}

This is great, until you want to write some specific tests for an unexported identifier. Imagine we add a multiply function that we want to test directly alongside our existing tests.

square.go
package math

func Square(a int) int {
  return multiply(a,a)
}

func multiply(a, b int) int {
  return a * b
}

Because the multiply function is unexported we cannot access it in the math_test package. What we can do however, is make this function exported only when running tests. To do this, we add a new file export_test.go that exports the multiply function in the math package.

export_test.go
package math

var Multiply = multiply

We can now write tests that use this exported identifier instead ๐ŸŽ‰

square_test.go
package math_test

import (
  "testing"

  "path.to/math"
)

func TestSquare(t *testing.T) {
    if result := math.Square(2); result != 4 {
      t.Errorf("Exected Square(2) to equal 4 but got %d",  result)
    }
}

func TestMultiply(t *testing.T) {
    if result := math.Multiply(1, 2); result != 2 {
      t.Errorf("Exected Multiply(1, 2) to equal 2 but got %d",  result)
    }
}