White box and Black box testing in Go
Tags: 100daystooffload, go, testing, programming
Published: 2024-02-25 12:00:39

Go has everything packaged from the beginning to getting started with testing your code. The language prefers conventions over configuration. By adhering to common naming conventions, Go projects minimize the need for configuring project-specific styles or rules. This is something that the tools for testing is using too of course.

To begin the journey with [white box](https://en.wikipedia.org/wiki/White-box_testing) and [black box](https://en.wikipedia.org/wiki/Black-box_testing) testing we will use a simple package, a calculator, defined in the file `calculator.go`.

```golang
package calculator

// Calculator defines a simple calculator with basic operations.
type Calculator struct{}

func (c *Calculator) Add(a, b int) int {
	return a + b
}

func (c *Calculator) Subtract(a, b int) int {
	return a - b
}

func (c *Calculator) Multiply(a, b int) int {
	return a * b
}

func isZero(n int) bool {
	return n == 0
}

func (c *Calculator) Divide(a, b int) int {
	if isZero(b) {
		panic("division by zero")
	}

	return a / b
}
```

Our tests will live in other files called, `calculator_white_box_test.go` and `calculator_black_box_test.go`, here is a convention that is important. For the testing tool to find our test-files we will need to use the suffix, `_test`, in the filename. The build tool will also exclude this files in the produced binary.

Before we go any further, lets define in simple terms what we mean with white box and black box testing.

**White box testing** - This refers to the possibility to test all code in your package, both private and public. Therefore all the internal structures and functions (all source code) are available for the tests.

**Black box testing** - This approach focus more on the functionality since only the public API of the package you are testing is available. The internal implementation of the package is not considered (or available) during these kind of tests.

Ok, so the `calculator_white_box_test.go` file could look like this.

```golang
package calculator

import (
	"testing"
)

func TestAdd(t *testing.T) {
	c := Calculator{}
	result := c.Add(1, 2)
	if result != 3 {
		t.Errorf("Expected 3, but got %d", result)
	}
}

func TestIsZero(t *testing.T) {
	if !isZero(0) {
		t.Errorf("Expected true, but got false")
	}
	if isZero(1) {
		t.Errorf("Expected false, but got true")
	}
}
```

The convention here is if the package name in the test file has the same name as the package we are testing, then this can be considered white box testing. This will enable the possibility to use private functions as `isZero` in the tests. Which can be convenient sometimes.

Let us make a file for the black box testing also, `calculator_black_box_test.go`.

```golang
package calculator_test

import (
	"testing"

	calculator "white_black_box_testing"
)

func TestDivide(t *testing.T) {
	c := calculator.Calculator{}
	result := c.Divide(8, 2)
	if result != 4 {
		t.Errorf("Expected 4, but got %d", result)
	}
}

func TestDivideByZero(t *testing.T) {
	c := calculator.Calculator{}
	defer func() {
		if err := recover(); err == nil {
			t.Errorf("Expected panic for division by zero, but got none")
		}
	}()
	c.Divide(8, 0)
}
```

Notice that the package name is, `calculator_test`, in this case. That's why we need to import the calculator package. Because of this we only have access to the public API in that package, and therefore we can only do black box testing. So in this file we would not be able to test the `isZero` function as we did in the previous test file.

One more convention to notice if you haven't written tests before in Go, is that each test function must start with the prefix, `Test`, to enable the test tool to see that test. Without it, the test will never run.

This is how my `go.mod` file looks like for completeness of this example.

```mod
module white_black_box_testing

go 1.22.0
```

Which approach should you use? As always, it depends, however I prefer black box testing in most cases.

If you want to learn more about testing your Go code then I can highly recommend this tutorial, [Learn Go with Tests](https://quii.gitbook.io/learn-go-with-tests/).

Happy testing!