質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

解決済

2回答

8531閲覧

goのhttpクライアントのテストをしたいのですがエラーで困っています

kexi

総合スコア16

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2015/11/02 08:52

httpでテキストを取得するプログラムのテストケースを書いていますがgo testするとエラーになってしまいます。実行はできています。
Goを初めて間もないのでどうしたらいいか困っています。

go testの結果

bash

1$ go test 2--- FAIL: TestFetch (0.00s) 3panic: runtime error: invalid memory address or nil pointer dereference [recovered] 4 panic: runtime error: invalid memory address or nil pointer dereference 5[signal 0xc0000005 code=0x1 addr=0x0 pc=0x486cce]

メインソース
main.go

go

1package main 2 3import ( 4 "fmt" 5 "net/http" 6 "io/ioutil" 7) 8func main() { 9 fmt.Println(Fetch("http://dyn.value-domain.com/cgi-bin/dyn.fcg?ip")) 10} 11func Fetch(url string) (ip string, err error) { 12 c, e := http.Get(url) 13 defer c.Body.Close() 14 if e != nil { 15 err = e 16 return 17 } 18 b, _ := ioutil.ReadAll(c.Body) 19 return string(b), nil 20}

テストソース
main_test.go

go

1package main 2 3import ( 4 "testing" 5 "fmt" 6 "net/http" 7 "net/http/httptest" 8) 9 10func TestFetch(t *testing.T) { 11 ts := httptest.NewServer(nil) 12 defer ts.Close() 13 path := "/path/to/ip" 14 expected := "1.2.3.4" 15 http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { 16 fmt.Fprint(w, expected) 17 }) 18 actual, err := Fetch(ts.Config.Addr + path) 19 if err != nil { 20 t.Errorf("%s", err) 21 } 22 if actual != expected { 23 t.Errorf("got %v want %s", actual, expected) 24 } 25}

よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

[signal 0xc0000005 code=0x1 addr=0x0 pc=0x486cce]
の後に、スタックトレースが出ていないでしょうか?それを見れば、どこでランタイム例外が発生しているのかわかるはずです。

ただコードに1点不審な点があります。

Go

1 c, e := http.Get(url) 2// defer c.Body.Close() // これはifの後に持ってくるべき 3 if e != nil { 4 err = e 5 return 6 } 7 defer c.Body.Close()

deferで登録しているClose処理は、http.Get()の成否を確認してから行うべきです。
おそらくここで失敗しているにもかかわらず、変数cへアクセスしているのが原因だと思います。

投稿2015/11/02 09:31

shanxia

総合スコア1038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kexi

2015/11/02 10:15

deferは関数のスコープを外れた時に実行されるものだと思っていました。
shanxia

2015/11/02 10:18

実行タイミングについては、ご認識の通り、関数のスコープを外れたときにClose()が実行されます。 今回の場合は、deferで遅延実行を登録する際、変数cの中のBodyや、Body内のClose()メソッドにアクセスしていますよね? その際にランタイムエラーが発生しているのだと思います。
kexi

2015/11/02 10:29 編集

なるほど。少し試してみます。 goroutine 5 [running]: testing.tRunner.func1(0xc08205c120) c:/go/src/testing/testing.go:450 +0x178 _/C_/Users/Kei/WebstormProjects/xrea_ssh.Fetch(0x777b50, 0xb, 0x0, 0x0, 0x0, 0x0) C:/Users/Kei/WebstormProjects/xrea_ssh/main.go:24 +0x24c _/C_/Users/Kei/WebstormProjects/xrea_ssh.TestFetch(0xc08205c120) C:/Users/Kei/WebstormProjects/xrea_ssh/main_test.go:18 +0x179 testing.tRunner(0xc08205c120, 0x905e00) c:/go/src/testing/testing.go:456 +0x9f created by testing.RunTests c:/go/src/testing/testing.go:561 +0x874 goroutine 1 [chan receive]: testing.RunTests(0x8021c8, 0x905e00, 0x1, 0x1, 0x4f0601) c:/go/src/testing/testing.go:562 +0x8b4 testing.(*M).Run(0xc082069ed8, 0x4f07aa) c:/go/src/testing/testing.go:494 +0x77 main.main() _/C_/Users/Kei/WebstormProjects/xrea_ssh/_test/_testmain.go:54 +0x11d exit status 2 FAIL _/C_/Users/Kei/WebstormProjects/xrea_ssh 2.699s
guest

0

ベストアンサー

httptestパッケージのExamplesの通りに作ればテストが通りましたよ。

go

1package main 2 3import ( 4 "fmt" 5 "net/http" 6 "net/http/httptest" 7 "testing" 8) 9 10func TestFetch(t *testing.T) { 11 expected := "1.2.3.4" 12 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 13 fmt.Fprint(w, expected) 14 })) 15 defer ts.Close() 16 actual, err := Fetch(ts.URL) 17 if err != nil { 18 t.Errorf("%s", err) 19 } 20 if actual != expected { 21 t.Errorf("got %v want %s", actual, expected) 22 } 23}

リクエストURLチェック追加版
参考: Goで外部リクエストが関わる処理をテストする

go

1package main 2 3import ( 4 "fmt" 5 "net/http" 6 "net/http/httptest" 7 "testing" 8) 9 10func TestFetch(t *testing.T) { 11 path := "/path/to/ip" 12 expected := "1.2.3.4" 13 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 14 if g, w := r.URL.Path, path; g != w { 15 t.Errorf("request got path %s, want %s", g, w) 16 } 17 fmt.Fprint(w, expected) 18 })) 19 defer ts.Close() 20 actual, err := Fetch(ts.URL + path) 21 if err != nil { 22 t.Errorf("%s", err) 23 } 24 if actual != expected { 25 t.Errorf("got %v want %s", actual, expected) 26 } 27}

投稿2015/11/02 09:23

編集2015/11/02 11:24
shiena

総合スコア1825

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kexi

2015/11/02 09:29

ありがとうございます。おかげさまで解決しました! 見ていたはずなんですけどね;;
shiena

2015/11/02 09:32

思い通りに動かないのは大抵自分のせいなので、参考にしたものと違いがないかじっくり見比べるのが肝要です。
kexi

2015/11/02 10:08

少し考えましたが、これだと/path/to/ipにアクセスしたかどうかわかりません。 http.HandlerFuncを作りこまないといけないのでしょうか?
shiena

2015/11/02 11:25

リクエストURLのチェックで参考になるページがありましたので追加しました。 実はこの辺りをちゃんとやった事なかったので私も勉強になりました。
kexi

2015/11/02 11:54

ありがとうございます。まさに求めていたものです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問