簡體   English   中英

golang中如何測試主要的包函數?

[英]How to test the main package functions in golang?

我想測試我的主包中包含的一些函數,但我的測試似乎無法訪問這些函數。

我的示例 main.go 文件如下所示:

package main

import (
    "log"
)

func main() {
    log.Printf(foo())
}

func foo() string {
    return "Foo"
}

我的 main_test.go 文件看起來像:

package main

import (
    "testing"
)

func Foo(t testing.T) {
    t.Error(foo())
}

當我運行go test main_test.go我得到

# command-line-arguments
.\main_test.go:8: undefined: foo
FAIL    command-line-arguments [build failed]

據我了解,即使我將測試文件移到其他地方並嘗試從 main.go 文件導入,我也無法導入它,因為它是package main

構建此類測試的正確方法是什么? 我應該從main包中刪除所有內容,除了一個簡單的主函數來運行所有內容,然后在自己的包中測試這些函數,還是有辦法讓我在測試期間從主文件中調用這些函數?

在命令行上指定文件時,必須指定所有文件

這是我的運行:

$ ls
main.go     main_test.go
$ go test *.go
ok      command-line-arguments  0.003s

請注意,在我的版本中,我在命令行上同時運行了main.go和main_test.go

此外,您的_test文件不太正確,您需要將測試函數稱為TestXXX並指向測試.T

這是修改過的verison:

package main

import (
    "testing"
)

func TestFoo(t *testing.T) {
    t.Error(foo())
}

和修改后的輸出:

$ go test *.go
--- FAIL: TestFoo (0.00s)
    main_test.go:8: Foo
FAIL
FAIL    command-line-arguments  0.003s

單元測試只到目前為止。 在某些時候,你必須實際運行該程序。 然后你測試它是否與實際輸入一起工作,從真實來源,產生實際輸出到真實目的地。 真的。

如果你想對單元進行單元測試,請將其移出main()。

不是 OP問題的直接答案,我總體上同意先前的答案和評論,敦促main應該是打包函數的調用者。 話雖這么說,這是我發現有用的測試可執行文件的方法。 它使用log.Fatalnexec.Command

  1. 使用延遲函數編寫main.go ,該函數調用log.Fatalln()以在返回之前將消息寫入stderr。
  2. main_test.go ,使用exec.Command(...)cmd.CombinedOutput()來運行程序,並選擇參數來測試某些預期結果。

例如:

func main() {
    // Ensure we exit with an error code and log message
    // when needed after deferred cleanups have run.
    // Credit: https://medium.com/@matryer/golang-advent-calendar-day-three-fatally-exiting-a-command-line-tool-with-grace-874befeb64a4
    var err error
    defer func() {
        if err != nil {
            log.Fatalln(err)
        }
    }()

    // Initialize and do stuff

    // check for errors in the usual way
    err = somefunc()
    if err != nil {
        err = fmt.Errorf("somefunc failed : %v", err)
        return
    }

    // do more stuff ...

 }

main_test.go ,測試應該導致somefunc失敗的錯誤參數可能如下所示:

func TestBadArgs(t *testing.T) {
    var err error
    cmd := exec.Command(yourprogname, "some", "bad", "args")
    out, err := cmd.CombinedOutput()
    sout := string(out) // because out is []byte
    if err != nil && !strings.Contains(sout, "somefunc failed") {
        fmt.Println(sout) // so we can see the full output 
        t.Errorf("%v", err)
    }
}

請注意,來自CombinedOutput() err是來自log.Fatalln對os.Exit(1)調用的非零退出代碼。 這就是我們需要用out來從somefunc提取錯誤消息的somefunc

exec包還提供cmd.Runcmd.Output 對於某些測試,這些可能比cmd.CombinedOutput更合適。 我還發現有一個TestMain(m *testing.M)函數可以在運行測試之前和之后進行設置和清理。

func TestMain(m *testing.M) {
    // call flag.Parse() here if TestMain uses flags
    os.Mkdir("test", 0777) // set up a temporary dir for generate files

    // Create whatever testfiles are needed in test/

    // Run all tests and clean up
    exitcode := m.Run()
    os.RemoveAll("test") // remove the directory and its contents.
    os.Exit(exitcode)

如何使用標志測試main並斷言退出代碼

@MikeElis 的回答讓我成功了一半,但是缺少 Go 自己的 flag_test.go 幫助我弄清楚的主要部分。

免責聲明

您本質上想要運行您的應用程序並測試正確性。 因此,請隨意標記此測試並將其歸檔在該類別中。 但值得嘗試這種類型的測試並看到好處。 特別是如果您正在編寫 CLI 應用程序。

這個想法是像往常一樣運行go test ,並且

  1. 使用go test制作的應用程序的測試版本在子流程中“自己”運行單元測試(參見第86行)
  2. 我們還將環境變量(參見第88行)傳遞給子進程,該子進程將執行將運行main並導致測試以main的退出代碼退出的代碼部分:
     if os.Getenv(SubCmdFlags) != "" { // We're in the test binary, so test flags are set, lets reset it so // so that only the program is set // and whatever flags we want. args := strings.Split(os.Getenv(SubCmdFlags), " ") os.Args = append([]string{os.Args[0]}, args...) // Anything you print here will be passed back to the cmd.Stderr and // cmd.Stdout below, for example: fmt.Printf("os args = %v\\n", os.Args) // Strange, I was expecting a need to manually call the code in // `init()`,but that seem to happen automatically. So yet more I have learn. main() }
    注意:如果 main 函數沒有退出,測試將掛起/循環。
  3. 然后對從子流程返回的退出代碼進行斷言。
     // get exit code. got := cmd.ProcessState.ExitCode() if got != test.want { t.Errorf("got %q, want %q", got, test.want) }
    注意:在此示例中,如果返回預期退出代碼以外的任何內容,則測試會從子進程中輸出 STDOUT 和/或 STDERR,以幫助調試。

在此處查看完整示例: go-gitter:測試 CLI

因為你只為測試設置了一個文件,所以不會使用其他的go文件。

運行go test而不是go test main_test.go

TestFoo(t *testing.T)測試函數簽名Foo(t testing.T)更改為TestFoo(t *testing.T)

在兩個來源中將包名稱從main更改為foobar。 在src / foobar下移動源文件。

mkdir -p src/foobar
mv main.go main_test.go src/foobar/

確保將GOPATH設置為src / foobar所在的文件夾。

export GOPATH=`pwd -P`

測試它

go test foobar

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM