Tucker의 Go 언어 프로그래밍 책과 유튜브를 통해 학습 중입니다.
테스트 환경 구성
- 기존에 사용했던 디렉터리에서 새로운 디렉터리를 만들고 새 파일을 만들어 아래와 같이 수정함.
//main.go
package main
import (
"Users/<path>/Web/myapp"
"net/http"
)
func main() {
http.ListenAndServe(":3000", myapp.NewHttpHandler())
}
//app.go (New File)
package myapp
import (
"encoding/json"
"fmt"
"net/http"
"time"
)
type User struct {
FirstName string `json:"First_name"`
LastName string `json:"Last_name"`
Email string `json:"email"`
CreatedAt time.Time `json:"Created_at"`
}
type fooHandler struct{}
// ServeHTTP implements http.Handler.
func (f *fooHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
user := new(User)
err := json.NewDecoder(r.Body).Decode(user)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprint(w, "Bad Requset: ", err)
return
}
user.CreatedAt = time.Now()
data, _ := json.Marshal(user)
w.Header().Add("content-type", "application/json") // JSON 포맷임을 표시
w.WriteHeader(http.StatusCreated)
fmt.Fprint(w, string(data))
}
func barHandler(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
if name == "" {
name = "World"
}
fmt.Fprintf(w, "Hello %s!", name)
}
func NewHttpHandler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World")
})
mux.HandleFunc("/bar", barHandler)
mux.Handle("/foo", &fooHandler{})
return mux
}
- 위와 같이 코드를 수정하고 다시 Debugging하고 웹에서 localhost:3000, /bar, /foo 호출하여 확인.
테스팅 파일 생성
- myapp 디렉터리에 app_test.go 파일을 생성
(go는 컨벤션이 <이름>_test 라고 붙이면, 테스트 코드처럼 작동함)
* 테스트 패키지 설치하기 (https://github.com/smartystreets/goconvey)
- 테스크 코드 테스트 하기 매우 좋은 패키지로 열심히 시도해도 계속 에러가 나서 GitHub을 읽어보니...
"Currently this means Go 1.16 and Go 1.17 are supported." 버전을 탑니다 ㅎ 전 1.23이거든요... 없이 합시다
- 그래도 설치하면 go test 명령어를 통해 확인할 수 있으니 설치해서 확인하는 것을 추천!
처음에 Github대로 바로 install 하면 맥북 기준으로 아래와 같이 패키지 제공하지 않는다고 나오니, get → install 하기
# go install github.com/smartystreets/goconvey
no required module provides package github.com/smartystreets/goconvey; to add it:
go get github.com/smartystreets/goconvey
- 기존 app.go에서 mux.HandleFun중 "/" 최상위 경로 Func을 아래와 같이 분리.
(맨 위에 func으로 옮김)
//app.go
func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World")
}
...
func NewHttpHandler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", indexHandler)
mux.HandleFunc("/bar", barHandler)
mux.Handle("/foo", &fooHandler{})
return mux
}
- 테스트 코드를 작성하면, Tucker님은 goconvey로 결과 값을 받지만 나는 받을 수가 없음
대신 goconvey를 설치하면 터미널에서 go test 명령어를 통해 결과 값을 받을 수 있음!
test 코드가 있는 디렉터리로 경로 이동 후 "go test" 실행
package myapp
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestIndexPathHandler(t *testing.T) {
res := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/", nil)
indexHandler(res, req)
if res.Code != http.StatusOK {
t.Fatal("Failed!!!", res.Code)
}
}
- 실패코드는 Status를 BedRequest로 변경해서 확인해보기
400이 와야하는데 200(StatusOK)이 와서 실패함.
if res.Code != http.StatusBadRequest {
t.Fatal("Failed!!!", res.Code)
}
// Status가 BedRequest일 때 OK
* assert 패키지
- https://github.com/stretchr/testify/tree/master/assert 를 사용
- 새로운 터미널 열어서 go get github.com/stretchr/testify/assert 실행 (assert 패키지만 가져옴)
- import 부분에 "github.com/stretchr/testify/assert" 패키지 추가
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
✓ assert를 사용하여 테스트 코드 만들기
package myapp
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestIndexPathHandler(t *testing.T) {
assert := assert.New(t)
res := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/", nil)
indexHandler(res, req)
assert.Equal(http.StatusOK, res.Code)
}
✓ 새로운 테스트 코드
내가 사용하는 버전에서는 ioutil이 없는 것 같고, 유튜브 댓글 통해 io로 사용하면 된다고 확인함 (버전 업글시 바뀐듯)
package myapp
import (
"io"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestIndexPathHandler(t *testing.T) {
assert := assert.New(t)
res := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/", nil)
indexHandler(res, req)
assert.Equal(http.StatusOK, res.Code)
data, _ := io.ReadAll(res.Body)
assert.Equal("Hello World", string(data))
}
✓ BarHandler 테스트 코드 추가
func TestBarPathHandler_Withoutname(t *testing.T) {
assert := assert.New(t)
res := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/bar", nil)
barHandler(res, req)
assert.Equal(http.StatusOK, res.Code)
data, _ := io.ReadAll(res.Body)
assert.Equal("Hello World", string(data))
}
- 저장 후에 go test를 돌리면, Fail이 발생하고 내용을 보면 실제 "Hello world!"가 왔다는 것을 확인할 수 있음.
assert.Equal("Hello World!", string(data))
- assert.Equal의 Hello World 뒤에 !를 붙이고 저장해서 다시 go test를 돌리면 PASS되는 것을 확인할 수 있음.
✓ BarHandler에서 req 경로를 "/bar" → "/" 로 변경 후 실행해도 PASS가 됨.
"/"일 때는 "Hello World"가 와야하는데 "Hello World!"가 온 것.
mux를 제대로 사용하지 않고 barHandler를 직접 호출해서 타겟이 제대로 적용이 되지 않은 것.
mux 코드를 추가하여 mux.ServeHTTP로 res,req를 호출해야 mux가 타겟에 맞춰 분배해서 호출함.
func TestBarPathHandler_Withoutname(t *testing.T) {
assert := assert.New(t)
res := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/", nil)
mux := NewHttpHandler()
mux.ServeHTTP(res, req)
assert.Equal(http.StatusOK, res.Code)
data, _ := io.ReadAll(res.Body)
assert.Equal("Hello World!", string(data))
}
- 테스트 결과를 보면 "Hello World!"가 와야하는데 "Hello World"가 와서 FAIL 되었다는 것을 확인할 수 있음.
Index경로로 핸들러가 호출된 것을 알 수 있음. (mux로 바꿔 "/" 가 동작한다는 것)
✓ BarHandler에 "/bar"로 타겟을 바꿔주고, IndexHandler에 동일하게 mux 코드를 추가하고 테스트 실행하면 OK되는 것을 확인할 수 있음.
func TestIndexPathHandler(t *testing.T) {
assert := assert.New(t)
res := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/", nil)
mux := NewHttpHandler()
mux.ServeHTTP(res, req)
assert.Equal(http.StatusOK, res.Code)
data, _ := io.ReadAll(res.Body)
assert.Equal("Hello World", string(data))
}
func TestBarPathHandler_Withoutname(t *testing.T) {
assert := assert.New(t)
res := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/bar", nil)
mux := NewHttpHandler()
mux.ServeHTTP(res, req)
assert.Equal(http.StatusOK, res.Code)
data, _ := io.ReadAll(res.Body)
assert.Equal("Hello World!", string(data))
}
✓ 타겟에 name을 넣어 코드를 copy/paste 하기
func TestBarPathHandler_Withname(t *testing.T) {
assert := assert.New(t)
res := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/bar?name=hee", nil)
mux := NewHttpHandler()
mux.ServeHTTP(res, req)
assert.Equal(http.StatusOK, res.Code)
data, _ := io.ReadAll(res.Body)
assert.Equal("Hello hee!", string(data))
}
'Language > Golang' 카테고리의 다른 글
Golang (Go언어) Go로 만드는 웹 (4) (0) | 2025.01.09 |
---|---|
Golang (Go언어) Go로 만드는 웹 (4) (0) | 2025.01.08 |
Golang (Go언어) Go로 만드는 웹 (2) (2) | 2025.01.03 |
Golang (Go언어) Go로 만드는 웹 (1) (0) | 2025.01.02 |
Golang (Go언어) 제네릭 프로그래밍(Generic Programming) 3/3 (0) | 2025.01.01 |