2015-12-25 7 views
7

免責事項:私はあなたにメリーXMasが欲しいと私は私の質問があなたを邪魔しないことを願っています!CLIテストのための "fmt" golangライブラリパッケージを扱う方法

sample.go:

package main 

import(
    "fmt" 
    "os" 
) 


type sample struct { 
    value int64 
} 

func (s sample) useful() { 
    if s.value == 0 { 
     fmt.Println("Error: something is wrong!") 
     os.Exit(1) 
    } else { 
     fmt.Println("May the force be with you!") 
    } 
} 

func main() { 
    s := sample{42} 
    s.useful() 

    s.value = 0 
    s.useful() 
} 

// output: 
// May the force be with you! 
// Error: something is wrong! 
// exit status 1 

私はgolangテストでインターフェイスを使用する方法について多くの研究を行いました。しかし、これまでのところ、私は完全にこの周りに私の頭を包むことができませんでした。少なくとも、私が "嘲笑"(この言葉を使用することに謝罪)する必要があるとき、インタフェースが私にどのように役立つかはわかりません。 "fmt"のようなライブラリパッケージ。

私は2つのシナリオを思い付いた:私はコントロールを持っているし、出力をチェックすることができる午前

  1. ラップFMTにパッケージをコマンドラインインターフェイスをテストするために使用するOS/execの文字列

どちらのシナリオも好きではない:

  1. 私は、実際のコマンドラインに畳み込まれたものではありません(下記参照)。移植性の問題もあります。
  2. 私はこの方法を検討していますが、fmtパッケージをラップすることは、少なくともテストのためのパッケージをラップすることで多大な作業になるかもしれないと懸念しています。

実際の質問:別の(より良い/より単純な/慣用的な)方法がありますか? 注:私は純粋なゴランでこれをやりたい、私は次のテストフレームワークに興味がありません。

cli_test.go:Kerninghamのブックの

package main 

import(
    "os/exec" 
    "testing" 
) 


func TestCli(t *testing.T) { 
    out, err := exec.Command("go run sample.go").Output() 
    if err != nil { 
     t.Fatal(err) 
    } 
    if string(out) != "May the force be with you!\nError: this is broken and not useful!\nexit status 1" { 
     t.Fatal("There is something wrong with the CLI") 
    } 
} 

答えて

8

第11章では、この質問への良い解決策を提供します。 トリックはos.Stdout

これは新しいにテストハーネスで上書きすることができますに初期化されて fmt.Fprint(アウト、...)へのコールにfmt.Printline()への呼び出しを変更することです(bytes.Buffer)を使用して、 テストで出力をキャプチャできます。

... sample.go https://github.com/adonovan/gopl.io/blob/master/ch11/echo/echo.gohttps://github.com/adonovan/gopl.io/blob/master/ch11/echo/echo_test.go

OPで編集

を参照してください:

package main 


import(
    "fmt" 
    "os" 
    "io" 
) 


var out io.Writer = os.Stdout // modified during testing 
var exit func(code int) = os.Exit 

type sample struct { 
    value int64 
} 


func (s sample) useful() { 
    if s.value == 0 { 
     fmt.Fprint(out, "Error: something is wrong!\n") 
     exit(1) 
    } else { 
     fmt.Fprint(out, "May the force be with you!\n") 
    } 
} 


func main() { 
    s := sample{42} 
    s.useful() 

    s.value = 0 
    s.useful() 
} 

// output: 
// May the force be with you! 
// Error: this is broken and not useful! 
// exit status 1 

cli_test.go:

package main 

import(
    "bytes" 
    "testing" 
) 


func TestUsefulPositive(t *testing.T) { 
    bak := out 
    out = new(bytes.Buffer) 
    defer func() { out = bak }() 

    s := sample{42} 
    s.useful() 
    if out.(*bytes.Buffer).String() != "May the force be with you!\n" { 
     t.Fatal("There is something wrong with the CLI") 
    } 

} 


func TestUsefulNegative(t *testing.T) { 
    bak := out 
    out = new(bytes.Buffer) 
    defer func() { out = bak }() 
    code := 0 
    osexit := exit 
    exit = func(c int) { code = c } 
    defer func() { exit = osexit }() 

    s := sample{0} 
    s.useful() 
    if out.(*bytes.Buffer).String() != "Error: something is wrong!\n" { 
     t.Fatal("There is something wrong with the CLI") 
    } 
    if code != 1 { 
     t.Fatal("Wrong exit code!") 
    } 
} 
+0

ワウを見て、私はパイクが本を書いたことを知りませんでした。あなたはタイトルまたは書籍への言及を述べてください。私はあなたの助言が好きです。私はそのようなコードをリファクタリングしようとしており、報告しています。どうもありがとうございます! – mark

+1

The Goプログラミング言語 http://www.gopl.io/ Alan A. A. Donovan・Brian W. Kernighan 2015年10月26日にペーパーバックで、11月20日に電子書籍に掲載されました Addison-Wesley; 380pp; ISBN:978-0134190440 – Amnon

+0

あなたのアドバイスに従ってコードをリファクタリングしました。それを明示するためにあなたの答えに出てきたことを加えたことに気にしないことを願っています。私が何か誤解した場合は、それを変更してください。ところで、os.Exitに問題があるようです。 – mark

2

私はここで何かが足りないか、あなたが午前testable examplesの話ですか?

基本的に、それはこのように動作します:*_test.goファイルでは、Tはあなたがサンプルコードとして、テスト可能な例を表示する方法のタイプとMプレースホルダーのプレースホルダです慣例Example[[T][_M]]に準拠する必要がありますGodoc。この関数がちょうどExample()と呼ばれる場合、コードはパッケージの例として表示されます。あなたの例のコードの最後の行の下

、あなたは今、この

// Output: 
// Foo 

ようgo testコメントを置くことができるテスト可能な例機能正確どちらかが// Output:以下のすべてを出していることを確認します(空白を含む)、テストが失敗します。ここで

func ExampleMongoStore_Get() { 

    sessionId := "ExampleGetSession" 

    data, err := ms.Get(sessionId) 

    if err == sessionmw.ErrSessionNotFound { 

    fmt.Printf("Session '%s' not found\n", sessionId) 

    data = make(map[string]interface{}) 
    data["foo"] = "bar" 

    ms.Save(sessionId, data) 
    } 

    loaded, _ := ms.Get(sessionId) 
    fmt.Printf("Loaded value '%s' for key '%s' in session '%s'", 
    loaded["foo"], 
    "foo", sessionId) 
    // Output: 
    // Session 'ExampleGetSession' not found 
    // Loaded value 'bar' for key 'foo' in session 'ExampleGetSession' 
} 

編集テスト可能な例えば実際の例です。the output of above example at godoc.org

関連する問題