먼저 기본틀을 만들고 시작합니다.
그 전에 Handler를 만들어 주어야 하는데 'myapp'이라는 폴더에 app.go라는 파일에 Handler를 만들어줍니다.
myapp/app.go
package myapp
import "net/http"
// NewHandler make a new myapp handler
func NewHandler() http.Handler {
mux := http.NewServeMux()
return mux
}
main.go
package main
import (
"net/http"
"./myapp"
func main() {
http.ListenAndServe(":3000", myapp.NewHandler())
}
이 상태에서 실행시키면 아무것도 뜨지 않는 것을 확인 할 수 있습니다.
이 상태에서 myapp폴더 안에 테스트 코드를 만들어 봅시다!
코드를 작성하기 전에 터미널 하나를 더 추가하여 goconvey를 실행시켜 놓읍시다!
myapp/app_test.go
package myapp
import "testing"
func TestIndex(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler()) // 1
defer ts.Close()
resp, err := http.Get(ts.URL) // 2
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode) // 3
}
1 : 저 부분을 통해 실제 웹 서버는 아니고 mock-up서버가 나오게 됩니다.
그 후 항상 닫아주어야 하기 때문에 defer로 함수가 끝나기 전에 닫아 줍니다.
2 : http.Get()안에 URL을 넣어야 하는데 test서버의 URL을 넣어주고, 이 return값은 response와 error가 나옵니다.
그래서 error가 없어야 하기 때문에 assert.NoError(err)로 작성해주고,
3 : resp.Code의 코드가 http.StatusOK 와 같아야 한다는 의미입니다.
이 상태로 저장하면 goconvey가 계속 테스트 하는 것을 볼 수 있습니다. 테스트 화면을 보면 404가 반환되는 것을 알 수 있는데
Handler를 등록하지 않아서 생긴 현상 입니다.
Handler를 등록하기 위해 myapp/app.go
로 돌아옵니다.
package myapp
import "net/http"
func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World")
}
// NewHandler make a new myapp handler
func NewHandler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", indexHandler)
return mux
}
이 상태에서 실행하면 빌드가 패스됐음을 알 수 있습니다.
이제 첫 번째 테스트는 끝났고, 두 번째 테스트를 해보도록 해봅시다! 결과가 Hello world가 나오는지 확인 해보도록 하려고 합니다.
다시 myapp/app_test.go
로 돌아와서
package myapp
import "testing"
func TestIndex(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Get(ts.URL)
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
data, _ := ioutil.ReadAll(resp.Body) // 1
assert.Equal("Hello World", string(data)) // 2
}
1 : ioutil을 통해 Body의 결과를 모두 읽어오고, 이 때 return 값은 data, error가 나오는데 지금은 error를 무시하기 때문에 다음과 같이 작성합니다.
2 : 읽은 data가 "Hello World"와 같아야 한다는 의미 입니다.
이 상태에서 저장하면 테스트가 진행 될 것이고, 아래와 같은 문구가 뜰 것입니다.
그럼 이제 TestIndex부분 테스트는 끝이 났고, 두 번째 테스트를 할 것입니다.
package myapp
import "testing"
func TestIndex(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Get(ts.URL)
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
data, _ := ioutil.ReadAll(resp.Body)
assert.Equal("Hello World", string(data))
}
func TestUsers(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Get(ts.URL + "/users")
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
data, _ := ioutil.ReadAll(resp.Body)
assert.Contains(string(data), "Get UserInfo")
}
구조는 TestIndex와 동일한데, URL만 기존 테스트 URL + /users를 추가한 상태입니다.
그 후 myapp/app.go
로 돌아와 Handler를 추가 해줍니다.
package myapp
import "net/http"
func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World")
}
func usersHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Get UserInfo by /users/{id}")
}
// NewHandler make a new myapp handler
func NewHandler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", indexHandler)
mux.HandleFunc("/users", usersHandler)
return mux
}
참고로 이렇게 추가해주는 이유는 mux.HandleFunc("/", indexHandler)
에서 하위 핸들러가 없으면 그 최상위 핸들러가
호출 되기 때문입니다.
그 후 myapp/app_test.go
로 돌아와서 수정해줍니다.
package myapp
import "testing"
func TestIndex(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Get(ts.URL)
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
data, _ := ioutil.ReadAll(resp.Body)
assert.Equal("Hello World", string(data))
}
func TestUsers(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Get(ts.URL + "/users")
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
data, _ := ioutil.ReadAll(resp.Body)
assert.Contains(string(data), "Get UserInfo") // 1
}
1 : app.go에 작성 했던 문자가 포함 되어 있어야 한다는 의미입니다.
그 후 저장 후 테스트를 하면 위와 같은 문구가 뜰텐데
정말로 제대로 되었는지 확인 해보죠!
그 전에 Get UserInfo가 들어와야 하는데 Hello World가 들어온게 아닌지 테스트 실패가 나는지 확인해봅시다!
assert.Contains(string(data), "Get UserInfo") 부분을 assert.Equal("Hello World", string(data))로 바꾸어 줍니다.
이 상태에서 저장 후 테스트를 해봅시다!
실패가 떴습니다! gocovey 화면에서 error문구를 살펴보면
정상적인 실패 화면이 떴음을 확인 할 수 있습니다.
그 후 테스트를 하나 더 추가합니다.
package myapp
import "testing"
func TestIndex(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Get(ts.URL)
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
data, _ := ioutil.ReadAll(resp.Body)
assert.Equal("Hello World", string(data))
}
func TestUsers(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Get(ts.URL + "/users")
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
data, _ := ioutil.ReadAll(resp.Body)
assert.Contains(string(data), "Get UserInfo")
func TestUserInfo(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Get(ts.URL + "/users/89") // 1
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
}
1 : http.Get으로 89번 유저의 정보를 가져오게 합니다.
우선 이 상태에서 PASS가 되는지 확인해보면 PASS가 뜰텐데 하위에 있는 부분이 정의가 안되어서 myapp/app.go
에 있는
상위 URL인 mux.HandleFunc("/users", usersHandler)
가 호출되어 PASS가 된 것 입니다.
그러면 data를 검증해봅시다!
data, _ := ioutil.ReadAll(resp.Body)
assert.Contains(string(data), "User Id:89")
를 TestUserInfo()안에 추가해준 뒤 확인해봅시다.
Fail이 떴고,
User Id:89 값이 포함이 되지 않았다는걸 확인 할 수 있습니다.
이것을 통과 시키려면 myapp/app.go
로 돌아와 Handler를 추가 해주어야 합니다.
package myapp
import (
"fmt"
"net/http"
)
func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World")
}
func usersHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Get UserInfo by /users/{id}")
}
func getUserInfo89Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "User Id:89")
}
// NewHandler make a new myapp handler
func NewHandler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", indexHandler)
mux.HandleFunc("/users", usersHandler)
mux.HandleFunc("/users/89", getUserInfo89Handler)
return mux
}
그 후 저장하면 테스트가 될 것 이고,
PASS 되었다는 것을 확인 할 수 있습니다.
문제는 Id값이 변할 수 있다는 것이다. 그렇기 때문에 usersURL뒤에 붙었을 때 파싱을 해주어야 하는데 r.URL.Path
를 사용하여 추출 해낼 수 있습니다. 하지만 그 과정이 복잡하기 때문에 있는 패키지를 사용하도록 하자.
여기에서 자세한 내용이 나옵니다.
go get -u github.com/gorilla/mux
이것을 카피하여 설치 해줍시다.
myapp/app.go
의 코드를 수정합시다.
package myapp
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World")
}
func usersHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Get UserInfo by /users/{id}")
}
func getUserInfo89Handler(w http.ResponseWriter, r *http.Request) {
mux.Vars(r) // 3
fmt.Fprint(w, "User Id:", vars["id"])
}
// NewHandler make a new myapp handler
func NewHandler() http.Handler {
mux := mux.NewRouter() // 1
mux.HandleFunc("/", indexHandler)
mux.HandleFunc("/users", usersHandler)
mux.HandleFunc("/users/{id:[0-9]+}", getUserInfo89Handler) // 2
return mux
}
1 : 이제 http.NewServeMux()가 아니라 gorillamux를 가지고 할 것 입니다.
2 : 여기에 들어가보면 해당 코드와 관련된 예제 코드가 나옵니다.
3 : mux.Vars(r)를 사용하면 알아서 파싱을 해줍니다.
이 상태에서 저장하면
PASS 되었다는 것을 확인 할 수 있고, users뒷부분에 id값을 적어주게 되면 거기에 해당하는 값이 파싱이 되는 것을 확인 할 수 있습니다.
풀소스
myapp/app_test.go
package myapp
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestIndex(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Get(ts.URL)
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
data, _ := ioutil.ReadAll(resp.Body)
assert.Equal("Hello World", string(data))
}
func TestUsers(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Get(ts.URL + "/users")
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
data, _ := ioutil.ReadAll(resp.Body)
assert.Contains(string(data), "Get UserInfo")
}
func TestGetUserInfo(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Get(ts.URL + "/users/89")
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
data, _ := ioutil.ReadAll(resp.Body)
assert.Contains(string(data), "User Id:89")
resp, err = http.Get(ts.URL + "/users/56")
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
data, _ = ioutil.ReadAll(resp.Body)
assert.Contains(string(data), "User Id:56")
}
myapp/app.go
package myapp
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World")
}
func usersHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Get UserInfo by /users/{id}")
}
func getUserInfoHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
fmt.Fprint(w, "User Id:", vars["id"])
}
// NewHandler make a new myapp handler
func NewHandler() http.Handler {
mux := mux.NewRouter()
mux.HandleFunc("/", indexHandler)
mux.HandleFunc("/users", usersHandler)
mux.HandleFunc("/users/{id:[0-9]+}", getUserInfoHandler)
return mux
}
main.go
package main
import (
"net/http"
"./myapp"
)
func main() {
http.ListenAndServe(":3000", myapp.NewHandler())
}
'프로그래밍(Web) > Golang' 카테고리의 다른 글
[바미] Go - RESTful API(DELETE) (0) | 2020.12.17 |
---|---|
[바미] Go - RESTful API(POST) (0) | 2020.12.17 |
[바미] Go - File Upload 만들기. (0) | 2020.12.16 |
[바미] Go - test환경 만들기 (0) | 2020.12.16 |
[바미] Go - 간단한 JSON Transfer 만들기. (0) | 2020.12.16 |