В Go как проверить, что интерфейс реализует все экспортированные методы struct? - PullRequest
0 голосов
/ 20 января 2020

Я работаю над библиотекой Go, в которой я использовал инструмент interfacer (https://github.com/rjeczalik/interfaces) для создания интерфейса из структуры и впоследствии запустил moq ( https://github.com/matryer/moq) для создания фиктивного объекта для этого интерфейса. Теперь я хотел бы написать модульный тест, который не проходит, если кто-то добавляет экспортированный метод в структуру без обновления интерфейса и макетов.

На высоком уровне мне кажется, что я мог бы получить reflect.Value интерфейса и структуры и вызовите NumMethod() на каждом, а затем убедитесь, что числа равны. Однако я изо всех сил пытаюсь реализовать эту идею.

Например, если я попробую это:

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())
}

Я могу позвонить, чтобы получить число методов person , но не из personInterface, так как эта паника с сообщением об ошибке

отражает: вызов рефлекса. Значение.НумМетод на ноль. Значение

Вот полное ошибка:

> 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

Как я могу получить число методов, реализованных interface, и в целом, как бы я go проверил, что интерфейс реализует все экспортируемые методы структуры?

1 Ответ

1 голос
/ 20 января 2020

Чтобы преобразовать комментарий mkopriva Go Playground в ответ, необходимо вызвать reflect.ValueOf() по указателю на интерфейс (PersonInterface), а затем необходимо вызвать Elem() для этого:

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())
}

На самом деле это похоже на процедуру установки значения, как описано в блоге «Три L aws of Reflection» (https://blog.golang.org/laws-of-reflection).

...