-1

I'm working on a Go library in which I've used the interfacer tool (https://github.com/rjeczalik/interfaces) to create an interface from a struct, and subsequently ran moq (https://github.com/matryer/moq) to generate a mock object for that interface. Now I would like to write a unit test that fails if someone adds an exported method to the struct without updating the interface and the mocks.

At a high level, it seems to me that I could get the reflect.Value of both the interface and the struct and call NumMethod() on each and then check that the numbers are equal. I'm struggling to implement this idea, however.

For example, if I try this:

package main

import (
    "fmt"
    "reflect"
)

type PersonInterface interface {
    GetName() string
}

type Person struct {
    Name string
}

func (person *Person) GetName() string {
    return person.Name
}

func main() {
    person := Person{}
    v := reflect.ValueOf(&person)
    fmt.Println(v.NumMethod())

    var personInterface PersonInterface
    w := reflect.ValueOf(personInterface)
    fmt.Println(w.NumMethod())
}

I'm able to call get the number of methods of the person, but not of the personInterface, as this panics with the error message

reflect: call of reflect.Value.NumMethod on zero Value

Here is the full error:

> go run assert_struct.go
1
panic: reflect: call of reflect.Value.NumMethod on zero Value

goroutine 1 [running]:
reflect.Value.NumMethod(0x0, 0x0, 0x0, 0x1)
    /usr/local/Cellar/go@1.12/1.12.12/libexec/src/reflect/value.go:1262 +0xc1
main.main()
    /Users/kurt/Documents/Scratch/assert_struct.go:27 +0x1a5
exit status 2

How could I get the number of methods implemented by an interface, and more generally, how would I go about checking that an interface implements all exported methods of a struct?

Kurt Peek
  • 52,165
  • 91
  • 301
  • 526

1 Answers1

1

To convert mkopriva's Go Playground comment to an answer, reflect.ValueOf() needs to be called on a pointer to the interface (PersonInterface) and then Elem() needs to be called on that:

package main

import (
    "fmt"
    "reflect"
)

type PersonInterface interface {
    GetName() string
}

type Person struct {
    Name string
}

func (person *Person) GetName() string {
    return person.Name
}

func main() {
    person := Person{}
    v := reflect.ValueOf(&person)
    fmt.Println(v.NumMethod())

    var personInterface PersonInterface
    w := reflect.ValueOf(&personInterface)
    fmt.Println(w.Elem().NumMethod())
}

This is actually similar to the procedure to make a value settable as described in the 'Three Laws of Reflection' blog (https://blog.golang.org/laws-of-reflection).

Kurt Peek
  • 52,165
  • 91
  • 301
  • 526