Unit Test Logs Only For Failed Inputs

Say we have a function that logs its inputs and result:

package add

import (
  "log"
)

func add(x, y int) int {
  log.Printf("add %d %d", x, y)
  res := x + y;
  log.Printf("add %d %d = %d", x, y, res)
  return res
}

And we have a failing unit test:

package add

import (
  "testing"
)

func TestAdd(t *testing.T) {
  inputs := []struct{
    x int
    y int
    want int
  }{{
    x: 1,
    y: 2,
    want: 3,
  }, {
    x: 3,
    y: 2,
    want: 5,
  }, {
    x: 4,
    y: 5,
    want: 0,  // fail
  }}
  for _, in := range inputs {
    got := add(in.x, in.y)
    if in.want != got {
      t.Errorf(
        "add %d %d got %d want %d",
        in.x, in.y, got, in.want)
    }
  }
}

The output also contains the logs of all passing inputs:

$ go test
2020/09/05 09:01:25 add 1 2
2020/09/05 09:01:25 add 1 2 = 3
2020/09/05 09:01:25 add 3 2
2020/09/05 09:01:25 add 3 2 = 5
2020/09/05 09:01:25 add 4 5
2020/09/05 09:01:25 add 4 5 = 9
--- FAIL: TestAdd (0.00s)
    add_test.go:28: add 4 5 got 9 want 0
FAIL
exit status 1

It would be better to only see the logs of the failing inputs. We can do that by logging to a buffer.

func add(logger *log.Logger, x, y int) int {
  logger.Printf("add %d %d", x, y)
  res := x + y
  logger.Printf("add %d %d = %d", x, y, res)
  return res
}
func TestAdd(t *testing.T) {
  inputs := []struct {
    x    int
    y    int
    want int
  }{{
    // ...
  }}
  for _, in := range inputs {
    var buf bytes.Buffer
    logger := log.New(&buf, "", log.LstdFlags)
    got := add(logger, in.x, in.y)
    if in.want != got {
      t.Errorf(
        "add %d %d log\n\n%s\ngot %d want %d",
        in.x, in.y, buf.String(), got, in.want)
    }
  }
}
$ go test
--- FAIL: TestAdd (0.00s)
    add_test.go:32: add 4 5 log

  2020/09/05 09:22:48 add 4 5
  2020/09/05 09:22:48 add 4 5 = 9

  got 9 want 0
FAIL
exit status 1

We could also use constructor dependency injection like this post: Unit Test Using Commands Instead Of Mocks.

Subscribe to my mailing list and get a free email course

* indicates required

Interests



Updated on 2020 Sep 5.

DISCLAIMER: This is not professional advice. The ideas and opinions presented here are my own, not necessarily those of my employer.