Макет встроенной структуры в Go Test - PullRequest
0 голосов
/ 20 сентября 2018

Дано:

// FileReader interface for reading from a file
type FileReader interface {
    ReadFile(filename string) ([]byte, error)
}

type FileRead struct {}

// ReadFile reads from filename fn using ioutilReadFile
func (fr FileRead) ReadFile(fn string) ([]byte, error) {
    return ioutil.ReadFile(fn)
}

type Dev struct {
    *FileRead
}

func NewDev() *Dev {
    frd := FileRead{}
    return &Dev{frd}
}

// Function that does some job
func (dev Dev) DoSomeStuff() {
    //...
    dev.ReadFile("file")
    //...
}

func main () {
    doer := NewDev()
    doer.DoSomeStuff()
}

Во время модульного тестирования операция ReadFile должна быть проверена.Как лучше всего добиться этого в тесте go?

Вместо этого struct Dev может использовать интерфейс FileReader, но тогда встраивание структуры больше не используется и синтаксис в DoSomeStuff становится менее очевидным.

1 Ответ

0 голосов
/ 20 сентября 2018

Если вы используете инфраструктуру DI, такую ​​как Dargo , вы можете внедрить что-то, что реализует FileReader, в dev.В вашем коде основной линии вы бы привязали обычный FileReader, но в своем тесте вы можете использовать фиктивный FileReader.Остальная часть вашего кода не должна знать разницу.Это выглядело бы примерно так:

import (
    "github.com/jwells131313/dargo/ioc"
    "io/ioutil"
    "testing"
)

type FileReader interface {
    ReadFile(filename string) ([]byte, error)
}

type FileRead struct{}

// ReadFile reads from filename fn using ioutilReadFile
func (fr FileRead) ReadFile(fn string) ([]byte, error) {
    return ioutil.ReadFile(fn)
}

type Dev struct {
    MyReader FileReader `inject:"FileReader"`
}

/* Not here anymore, but you can implement DargoInitializer
   if you need more initialization of Dev
func NewDev() *Dev {
    frd := FileRead{}
    return &Dev{frd}
}
*/

// Function that does some job
func (dev Dev) DoSomeStuff() {
    //...
    dev.MyReader.ReadFile("file")
    //...
}

var locator ioc.ServiceLocator

func initialize() error {
    l, err := ioc.CreateAndBind("Example", func(binder ioc.Binder) error {
        binder.Bind("Dev", &Dev{})
        binder.Bind("FileReader", &FileRead{})
        return nil
    })

    locator = l

    return err

}

func main() {
    initialize()

    raw, _ := locator.GetDService("Dev")
    doer := raw.(*Dev)

    doer.DoSomeStuff()
}

// Here is test code

type TestFileRead struct{}

// ReadFile is a mock that just returns a zero-length byte array
func (tfr TestFileRead) ReadFile(fn string) ([]byte, error) {
    return []byte{}, nil
}

func TestMe(t *testing.T) {
    initialize()

    ioc.BindIntoLocator(locator, func(binder ioc.Binder) error {
        binder.Bind("FileReader", &TestFileRead{}).Ranked(1)
        return nil
    })

    // Test Me!

}

В приведенном выше примере «нормальный» читатель файла внедряется в обычный код, но в тесте есть TestFileReader с более высоким рангом.Поэтому, когда вы пошли, чтобы получить Dev в тесте, в него был бы введен тестовый, а не тот, что из основного кода.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...