Golang으로 웹서버 만들기(2)

김영한·2020년 11월 10일
1

코드 Github
참고


📢 Test 환경 구성하기

WEB3 폴더에 작성했다.

테스팅 환경을 구축해놓으면 개발하기가 무척 편하다.

지난 시간까지 만들었던 mux를 만들어내는 코드들을 새로운 패키지로 만들 것이다.

WEB3 경로안에 myapp이라는 폴더를 하나 만들고 그 안에 app.go라는 파일을 만들어준다.

main.go 내용을 app.go로 옮겨주고 메인 함수 부분을 NewHttpHandler() 함수로 변경해준다.
app.go

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{})
	http.ListenAndServe(":3000", mux)
	return mux
}

http.Handler라는 리턴값으로 mux를 내보내고

메인 문에서는 mux를 리턴해주는 app.go의 메소드를 넣어준다.
main.go

func main() {
	http.ListenAndServe(":3000", myapp.NewHttpHandler())
}

app.go에 옮겨주는 작업은 끝났고 이제 테스팅 코드를 만들거다.

WEB3 폴더에 app_test.go파일을 만들어주는데 Go는 뒤에 _를 붙이고 test라고 하면 test코드로 작동한다.

테스트 코드는 함수명 앞에 Test라고 시작해야한다.
양식이 정해져있는데 t *testing.T -> testing 패키지에 T 포인터를 인자로 받아야한다.

func TestIndexPathHandler(t *testing.T) {
	
}

이제 패키지 하나를 설치해야한다.
goconvey : 백그라운드로 돌면서 파일이 갱신될 때마다 자동으로 테스트를 해준다.
설치법은 링크홈페이지에 나와있듯이 cmd로 들어가서
go get github.com/smartystreets/goconvey를 입력해주면 된다.
그 후에 자신의 WEB3의 디렉토리로 들어가서 goconvey를 입력해주면 실행이 된다.
그럼 goconvey가 웹 서버를 하나 돌려준다.(cmd를 끄면 안됨)

localhost:8080번에서 돌아간다.

TestIndexHandler가 성공했다고 나와있다.


🔔 이제 TestIndexHandler를 작성해보자.

func TestIndexPathHandler(t *testing.T) {
	res := httptest.NewRecorder() // 실제 네트워크를 사용하지않고 실행가능
	req := httptest.NewRequest("GET", "/", nil)

	indexHandler(res, req) // app.go에서 핸들러를 분리해줌

	if res.Code != http.StatusOK {
		t.Fatal("Failed!!", res.Code)
	}
}


마찬가지로 PASS된다.


💊 fail되는 경우

if res.Code != http.StatusBadRequest {
		t.Fatal("Failed!!", res.Code)
}

코드를 변경하고 기다려보면

fail되는 것을 볼 수 있다.


💊 매번 res.Code부분을 검사해주기 귀찮으니까 다른 패키지로 만들어주자.

stretchr에 testify에서 assert파일만 가져올 것이다.

다른 cmd를 열어서
go get github.com/stretchr/testify/assert를 입력하면 다운받을 수 있다.

import 부분에 "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) // 잘 돌아가는지 아닌지 검사
}

로 코드를 변경해준다.

assert 패키지를 가져와서 사용하면 알아서 매번 검사해준다.


실제 Body를 비교해보자
실제 Body값은 res.Body에 들어있다. 하지만 버퍼 클래스라 바로 가져올 수 없어서 ioutil.ReadAll()을 이용해서 버퍼 값을 읽어오자.

TestIndexPathHandler 메소드에 추가

data, _ := ioutil.ReadAll(res.Body)
	assert.Equal("Hello World", string(data))

마찬가지로 저장하면 알아서 확인해준다.(PASS뜸)


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, _ := ioutil.ReadAll(res.Body)
	assert.Equal("Hello World!", string(data))
}

💊 이제 barHandler를 직접 호출하지 말고 mux를 이용해서 호출해보자

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, _ := ioutil.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, _ := ioutil.ReadAll(res.Body)
	assert.Equal("Hello World!", string(data))
}

name과 함께 넣기

func TestBarPathHandler_WithName(t *testing.T) {
	assert := assert.New(t)

	res := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/bar?name=tucker", nil)

	mux := NewHttpHandler()
	mux.ServeHTTP(res, req)

	assert.Equal(http.StatusOK, res.Code)
	data, _ := ioutil.ReadAll(res.Body)
	assert.Equal("Hello tucker!", string(data))
}

전부 PASS되는 것을 볼 수 있다.


Json도 해주자

func TestFooHandler_WithJson(t *testing.T) {
	assert := assert.New(t)

	res := httptest.NewRecorder()
	req := httptest.NewRequest("POST", "/foo",
		strings.NewReader(`{"first_name":"tucker", "last_name":"kim", "email":"tucker@naver.com"}`))
	// 인자로 ioreader가 들어와야함. 따라서 string을 reader로 변경해서 넣어준다.

	mux := NewHttpHandler()
	mux.ServeHTTP(res, req)

	assert.Equal(http.StatusCreated, res.Code)
}

string을 reader로 변경해서 넣어줄 때 ""를 써야하므로 인자 전체를 ``로 묶어준다.

// 실제로 데이터가 잘 왔는지 검사해보자
user := new(User)
err := json.NewDecoder(res.Body).Decode(user) // decoder되었으므로 값이 들어와있음
assert.Nil(err)                               // 에러가 없어야한다.
assert.Equal("tucker", user.FirstName)
assert.Equal("kim", user.LastName)

전부 pass되는 것을 볼 수 있다.

1개의 댓글

comment-user-thumbnail
2021년 7월 23일

혹시 디버깅에서는 문자열이 틀렸다고 에러가 뜨는데 고컨베이에서는 pass가 나는 부분 어떻게 해결할수 있는지 아시는지요?

답글 달기