Zac Gross

Code & More

Go Asserts and Multiple Return Values

| Comments

Recently I have been writing many tests for functions with multiple return values. I was hoping to write a single line assertion. Something like the following:

1
2
3
4
5
6
7
8
   
  func testableFunc() (int,int,int){
      return 5,6,7
  }

  assert.Equal([]interface{}{5,6,7},testableFunc());

  //Note Equal()'s signature expects interface{} arguments

This won’t compile, the method signature for Equal takes interface{} parameters. Understandably the compiler can’t figure it out.

After checking the mailing list it turns out the compiler is smart enough to map multiple return values to function params when their types and order match. e.g:

1
2
3
4
5
6
7
8
9
10
   func testableFunc() (int,int,int){
      return 5,6,7
  }

  func anotherFunc(a int,b int, c int) int {
      return a + b + c
  }

  //valid because returned types match arguments
  anotherFunc(testableFunc())

With this behavior in mind we can write a shim function to map multiple return values to a slice of values that the assert function can compare. Here is a 2 value shim:

1
2
3
4
   
  func Shim(a, b interface{}) []interface{} {
      return []interface{}{a, b}
  }

It can be used like so

1
2
3
4
5
6
   
  func testableFunc() (int,int){
      return 5,5
  }

  assert.Equal(Shim(5,5),Shim(testableFunc()))

Now shorten the name and create shims for different number of return values.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   //Shim for 2 param return values
  func M(a, b interface{}) []interface{} {
      return []interface{}{a, b}
  }

  //Shim for 3 param return values
  func M3(a, b, c interface{}) []interface{} {
      return []interface{}{a, b, c}
  }

  //Shim for 4 param return values
  func M4(a, b, c, d interface{}) []interface{} {
      return []interface{}{a, b, c, d}
  }

  assert.Equal(M(5,5),M(someMethod))

And finally here is a complete working example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
   
  import (
      "github.com/stretchr/testify/assert"
      "testing"
  )

  //Shim for 2 param return values
  func M(a, b interface{}) []interface{} {
      return []interface{}{a, b}
  }

  //Shim for 3 param return values
  func M3(a, b, c interface{}) []interface{} {
      return []interface{}{a, b, c}
  }

  //Shim for 4 param return values
  func M4(a, b, c, d interface{}) []interface{} {
      return []interface{}{a, b, c, d}
  }

  func testableFunc() (int, int) {
      return 5, 5
  }

  func otherTestableFunc() (int, int, string) {
      return 6, 7, "hi"
  }

  func TestMulti(t *testing.T) {

      assert.Equal(t, M(5, 5), M(testableFunc()))
      assert.Equal(t, M3(6, 7, "hi"), M3(otherTestableFunc()))

  }

Comments