Tucker의 Go 언어 프로그래밍 책과 유튜브를 통해 학습 중입니다.
POST를 사용하여 테스트 진행하기
- Go로 만드는 웹(4) 포스팅에서 사용했던 프로젝트 그대로 사용하여 POST 테스트 진행하기
func TestCreateUser(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Post(ts.URL+"/users", "application/json", strings.NewReader(`{"first_name":"Joy", "last_name":"Kim", "email": "joy@mail.com"}`))
assert.NoError(err)
assert.Equal(http.StatusCreated, resp.StatusCode)
}
- string으로 json 형태로 Body를 사용하여 테스트 코드를 작성함.
그리고 'go test'로 확인하면, 201(StatusCreated)이 와야 하는데 200(StatusOK)이 와서 FAIL이 되는 것을 확인할 수 있음.
- 지난 번과 동일하게 app.go에 Handler 설정이 별도로 없어서 새로 만들어줌.
- User struct를 새로 만들고, createUserHandler도 새로 구성하여 테스트 진행.
// app.go
// User Struct
type User struct {
ID int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email`
CreateAt time.Time `json:"created_at"`
}
...
func createUserHandler(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, err)
return
}
// Create User
user.ID = 2
user.CreateAt = time.Now()
w.WriteHeader(http.StatusCreated)
data, _ := json.Marshal(user)
fmt.Fprint(w, string(data))
}
...
// NewHandler make a new my app Handler
func NewHandler() http.Handler {
mux := mux.NewRouter()
// mux := http.NewServeMux()
mux.HandleFunc("/", indexHandler)
mux.HandleFunc("/users", usersHandler).Methods("GET") // GET 메서드일 떄는 usersHandler로 작동되게
mux.HandleFunc("/users", createUserHandler).Methods("POST") // POST 메서드일 떄는 usersHandler로 작동되게
mux.HandleFunc("/users/{id:[0-9]+}", getUserInfoHandler)
return mux
}
- 'go test'를 통해 테스트를 진행하면 모두 PASS 가 되는 것을 확인할 수 있음.
// app_test.go
func TestCreateUser(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Post(ts.URL+"/users", "application/json", strings.NewReader(`{"first_name":"Joy", "last_name":"Kim", "email": "joy@mail.com"}`))
assert.NoError(err)
assert.Equal(http.StatusCreated, resp.StatusCode)
user := new(User)
err = json.NewDecoder(resp.Body).Decode(user)
assert.NoError(err)
assert.NotEqual(0, user.ID)
id := user.ID
resp, err = http.Get(ts.URL + "/usrs/" + strconv.Itoa(id))
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
user2 := new(User)
err = json.NewDecoder(resp.Body).Decode(user2)
assert.NoError(err) //Decod하는데 첫 번째 U가 먼저 옴 (Format이 안맞음.)
assert.Equal(user.ID, user2.ID)
assert.Equal(user.FirstName, user2.FirstName)
}
- Post로 user 데이터를 만들어서 Created 것을 확인했고, 전송된 내용을 읽어 제대로 생성이 된 것인지 확인하는 코드 생성
- 서버가 보낸 resp.Body를 읽어 User를 Decode하여 문제가 있는지 없는지 확인.
- User의 ID가 0이 아니고, User.ID를 받아 실제 User의 정보가 올 수 있도록 http.Get을 사용하여 확인
- 값이 왔을 때 error가 없어야하고, 응답의 상태가 StatusOK가 와야함.
- 데이터는 UserInfo가 Json 형태로 와야해서, user2를 만들어 Json으로 데이터를 읽음.
- user2와 user1은 ID가 같기에 같은 유저라 user와 user2가 같아야함.
→ 내가 이 error가 난 이유는 resp, err = http.Get(ts.URL + "/usrs/" + strconv.Itoa(id)) 여기 "usrs"라는 오타가 존재함. (오타...)
// app.go
package myapp
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
"github.com/gorilla/mux"
)
// User Struct
type User struct {
ID int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email`
CreateAt time.Time `json:"created_at"`
}
var userMap map[int]*User
var lastID int
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)
id, err := strconv.Atoi(vars["id"])
if err != nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprint(w, err)
return
}
user, ok := userMap[id]
if !ok {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "No User Id:", id)
return
}
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
data, _ := json.Marshal(user)
fmt.Fprint(w, string(data))
}
func createUserHandler(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, err)
return
}
// Create User
lastID++
user.ID = lastID
user.CreateAt = time.Now()
userMap[user.ID] = user
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
data, _ := json.Marshal(user)
fmt.Fprint(w, string(data))
}
// NewHandler make a new my app Handler
func NewHandler() http.Handler {
userMap = make(map[int]*User)
lastID = 0
mux := mux.NewRouter()
mux.HandleFunc("/", indexHandler)
mux.HandleFunc("/users", usersHandler).Methods("GET")
mux.HandleFunc("/users", createUserHandler).Methods("POST")
mux.HandleFunc("/users/{id:[0-9]+}", getUserInfoHandler)
return mux
}
- 이전에 getUserInfoHandler에 정보를 고정으로 기재해서 넣어놔서 해당 user.ID가 없다고 에러가 남.
- userMap을 만들어서 user가 create한 user정보를 등록해서 가지고 있다가 그 정보가 있으면 user정보를 리턴하고, 없으면 NoUserID를 리턴하는 코드 작성함.
- myapp.go에서 user 정보를 저장할 userMap을 생성함.
- NewHandler에 사용하기 전에 initialize 해줘야하기 때문에 Newhandler하기 전 initialize 먼저하게 만듦.
- Map에 user를 등록할 때는 user를 만들 때 등록할 것이라 Created User에서 유저 정보를 셋팅하고, UserMap에 user.ID값을 등록함.
- ID 값은 매번 변경되어야 하기때문에 마지막 ID를 가지고 있는 변수를 만들어 NewHandler에서 0으로 초기화 함.
- user가 만들어질 때마다 하나씩 증가 되게 코드를 하나 만들어 줌.
- getUserInfo는 실질적으로 request한 ID가 있으면 user 정보를 반환하게 하기 위해 mux에 vars를 만들어 request를 보내고, user가 보낸 정보가 들어오면, id를 뽑아와서 타입을 변경함.
- 에러가 있는 경우(변환 과정에 문제가 있으면) StatusBadRequest를 출력하고 에러가 무엇인지 알려줌.
- ID에 해당하는 User가 실제 Map에 있는지 확인하기 위해 userMap[id]에서 id에 해당하는 것이 있는지 확인.
- 만약 해당하는 ID가 없는 경우 헤더에서 HTTPStatusOK하고, User ID가 없음을 리턴함.
// app_test.go
package myapp
import (
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"strconv"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestIn(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, _ := io.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, _ := io.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, _ := io.ReadAll(resp.Body)
assert.Contains(string(data), "No User Id:89")
resp, err = http.Get(ts.URL + "/users/56")
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
data, _ = io.ReadAll(resp.Body)
assert.Contains(string(data), "No User Id:56")
}
func TestCreateUser(t *testing.T) {
assert := assert.New(t)
ts := httptest.NewServer(NewHandler())
defer ts.Close()
resp, err := http.Post(ts.URL+"/users", "application/json", strings.NewReader(`{
"first_name": "Joy",
"last_name": "Kim",
"email": "joy@mail.com"
}`))
assert.NoError(err)
assert.Equal(http.StatusCreated, resp.StatusCode)
user := new(User)
err = json.NewDecoder(resp.Body).Decode(user)
assert.NoError(err)
assert.NotEqual(0, user.ID)
id := user.ID
resp, err = http.Get(ts.URL + "/users/" + strconv.Itoa(id))
assert.NoError(err)
assert.Equal(http.StatusOK, resp.StatusCode)
user2 := new(User)
err = json.NewDecoder(resp.Body).Decode(user2)
assert.NoError(err)
assert.Equal(user.ID, user2.ID)
assert.Equal(user.FirstName, user2.FirstName)
}
해당 코드로 테스트를 진행하면 모두 PASS가 되는 것을 확인할 수 있음.
p.s 아... 강의 다시 듣고 다시 들어서 복습해야 할 듯합니다...
'Language > Golang' 카테고리의 다른 글
Golang (Go언어) Go로 만드는 웹 (4) (0) | 2025.01.09 |
---|---|
Golang (Go언어) Go로 만드는 웹 (4) (0) | 2025.01.08 |
Golang (Go언어) Go로 만드는 웹 (3) (0) | 2025.01.07 |
Golang (Go언어) Go로 만드는 웹 (2) (2) | 2025.01.03 |
Golang (Go언어) Go로 만드는 웹 (1) (0) | 2025.01.02 |