Рабочий процесс создания пакетов в Go

Я понимаю, что программы в Go запускаются из функции main в качестве отправной точки. Но мне было интересно, каков рабочий процесс для создания функций для нового пакета.

Например, в python я использую __main__ в модуле, когда модуль вызывается напрямую. Когда модуль импортируется из другого файла, __main__ будет игнорироваться. Это полезно, когда вы разрабатываете новый модуль.

if __name__ == "__main__":
    # Run module code here if module called directly

Для Go я использую файл test.go с package main вместе с моим файлом main.go для тестирования функций в создаваемых мной пакетах.

// test.go
package main

import (
    "newpackage"
)

func main() {
    newpackage.MyNewFunc()
}

Есть ли лучший способ сделать это или это стандартный рабочий процесс? Спасибо.


person AppTest    schedule 08.06.2017    source источник
comment
Да, есть: прочитайте golang.org/cmd/go/#hdr-Test_packages и golang.org/pkg/testing   -  person Volker    schedule 08.06.2017
comment
Выглядит странно импортировать основной пакет из других пакетов. Можете ли вы предоставить некоторые подробности, чтобы рассказать нам, почему у вас есть такой сценарий?   -  person Heissenberger    schedule 08.06.2017
comment
Я не уверен, что ты имеешь в виду. Я не пытаюсь импортировать основной пакет. Мне просто интересно, есть ли эквивалент Python if __name__ == "__main__":, который позволяет мне попробовать отдельные функции в модуле без необходимости писать тестовый файл. См. stackoverflow.com/a/4041260/5319281.   -  person AppTest    schedule 08.06.2017
comment
Но, как указывали другие, инструменты тестирования Go кажутся лучшим способом.   -  person AppTest    schedule 08.06.2017


Ответы (1)


Вы не тестируете Go, используя main. В Go есть собственный тестовый фреймворк.

Во-первых, прочитайте "Как писать код Go", в котором объясняются структура пакета Go и инструменты тестирования. Лучше всего использовать их, потому что многие инструменты Go предполагают именно такой макет.

При создании пакета поместите его где-нибудь в ~/go/src. Я бы рекомендовал следовать соглашению, используя репозиторий, который вам нравится использовать, даже для вещей, которые вы не обязательно собираетесь загружать. Это способствует лучшей организации; go get также поместит другие внешние пакеты в ~/go/src/.

Например, я бы использовал ~/go/src/github.com/schwern/newpackage/, хотя я не собираюсь загружать это на Github. github.com/schwern действует как моя «организация» в дереве исходного кода Go.

Поместите функции в newpackage.go под package newpackage.

$ cat ~/go/src/github.com/schwern/newpackage/newpackage.go 
package newpackage

func MyNewFunc() string {
    return "Hello!"
}

Затем тесты идут в newpackage_test.go рядом с newpackage.go. Они должны быть знакомы из Python, напишите кучу функций Test*. В отличие от Python, он не использует утверждения.

$ cat ~/go/src/github.com/schwern/newpackage/newpackage_test.go 
package newpackage_test

import(
    "testing"
    "github.com/schwern/newpackage"
)

func TestMyNewFunc( t *testing.T ) {
    want := "Hello!"
    have := newpackage.MyNewFunc()

    if have != want {
        t.Errorf("MyNewFunc(): have: '%v', want: '%v'", have, want )
    }
}

Если вы запустите go test внутри каталога пакета, он скомпилирует текущий пакет и его зависимости, найдет и скомпилирует все *_test.go файлы в каталоге пакета и выполнит их Test* функции.

$ pwd
/Users/schwern/go/src/github.com/schwern/newpackage
$ go test -v
=== RUN   TestMyNewFunc
--- PASS: TestMyNewFunc (0.00s)
PASS
ok      github.com/schwern/newpackage   0.013s

Обратите внимание, что тест находится в другом пакете, чем его тестирование. Это делает его тестом черного ящика, он может видеть только экспортированные (т.е. UpperCase) функции. Вы можете сделать тест в стеклянном ящике, поместив тесты в один и тот же пакет, лучше всего сделать это в отдельном файле, например newpackage_internal_test.go.

К сожалению, в Go нет функций assert, приведенный выше if и вызов t.Errorf эквивалентны. Вместо того, чтобы постоянно вручную сворачивать их, существуют библиотеки, которые предоставляют функции утверждения, такие как stvp/assert. После запуска go get github.com/stvp/assert вы можете написать...

package newpackage_test

import(
    "testing"
    "github.com/schwern/newpackage"
    "github.com/stvp/assert"
)

func TestMyNewFunc( t *testing.T ) {
    assert.Equal( t, newpackage.MyNewFunc(), "Hello!" )
}

Если вам нужен исполняемый файл, использующий newpackage, он, вероятно, должен находиться в отдельном пакете. Если только это не неотъемлемая часть newpackage.

$ cat ~/go/src/github.com/schwern/newexec/main.go 
package main

import (
    "fmt"
    "github.com/schwern/newpackage"
)

func main() {
    fmt.Println(newpackage.MyNewFunc())
}

Если вы хотите протестировать main, пакет testing предоставляет специальную функцию TestMain... хотя я признаю, что не совсем понимаю его. Как и в любом другом языке, лучше всего вложить в библиотечные вызовы как можно больше функций и сделать main тонкой оболочкой.

person Schwern    schedule 08.06.2017