728x90

요즘 핫하다는 TDD 와 핫한 언어 Golang 으로 TDD 를 찍먹해보겠습니다.

 

일단 간단한 웹 어플리케이션을 만들어줄게요

 

개발환경은 golang version 1.16 에서 진행되었습니다.

 

main.go

package main

import (
	"made-go/myapp"
	"net/http"
)

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

 

 

myapp/app.go

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{}
type barHandler struct{}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "hello world")
}

func (f *fooHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Query().Get("name")
	if name == "" {
		name = "World"
	}
	fmt.Fprintf(w, "Hello %s", name)
}

func (b *barHandler) 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 request: ", err)
		return
	}
	user.CreatedAt = time.Now()
	data, err := json.Marshal(user)
	w.Header().Add("content-type", "application/json")
	w.WriteHeader(http.StatusOK)
	fmt.Fprint(w, string(data))
}

func NewHttpHandler() http.Handler {
	mux := http.NewServeMux()
	mux.HandleFunc("/", indexHandler)

	mux.Handle("/foo", &fooHandler{})
	mux.Handle("/bar", &barHandler{})

	return mux
}

 

 

이글은 테스트 하는 방법을 설명하는 글로써 mux 나 http 에 대해서 자세한 설명은 생략하겠습니다.

 

go 에서 test 를 하기위해서는 파일 이름에 test가 들어가야 합니다.

폴더구조

app_test.go  를 만들어 줍니다.

package myapp

import (
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
)

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(res.Code, http.StatusOK)
	data, _ := ioutil.ReadAll(res.Body)
	assert.Equal("hello world", string(data))
}

func TestFooPathHandler_WithoutName(t *testing.T) {
	assert := assert.New(t)
	res := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/foo", nil)
	mux := NewHttpHandler()
	mux.ServeHTTP(res, req)

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

func TestFooPathHandler(t *testing.T) {
	assert := assert.New(t)
	res := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/foo?name=jongyun", nil)
	mux := NewHttpHandler()
	mux.ServeHTTP(res, req)

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

 

백그라운드에서 변경되는 코드를 감지하여 매번 테스팅을 해주는 goconvey 라는 라이브러리를 사용할것입니다.

https://github.com/smartystreets/goconvey

 

GitHub - smartystreets/goconvey: Go testing in the browser. Integrates with `go test`. Write behavioral tests in Go.

Go testing in the browser. Integrates with `go test`. Write behavioral tests in Go. - GitHub - smartystreets/goconvey: Go testing in the browser. Integrates with `go test`. Write behavioral tests i...

github.com

 

테스트 코드를 좀더 편하게 비교하고 테스트 할수 있게금 도와주는 testify 라는 라이브러리도 사용할게요

https://github.com/stretchr/testify

 

GitHub - stretchr/testify: A toolkit with common assertions and mocks that plays nicely with the standard library

A toolkit with common assertions and mocks that plays nicely with the standard library - GitHub - stretchr/testify: A toolkit with common assertions and mocks that plays nicely with the standard li...

github.com

 

go get github.com/smartystreets/goconvey
go get github.com/stretchr/testify

 

간단한 테스트 코드를 하나 작성 해보겠습니다.

myapp/app_test.go

package myapp

import (
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
)

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(res.Code, http.StatusOK)
	data, _ := ioutil.ReadAll(res.Body)
	assert.Equal("hello world", string(data))
}

 

코드를 작성하신뒤 터미널에서 goconvey 라고 실행하시면 http://localhost:8080 에서 테스트 코드가 돌아갈것입니다.

 

코드가 변경되면 알아서 감지해서 테스트를 돌려주니 개발하기 참 편할거 같습니다.

 

테스트 코드를 추가하고 일부러 에러도 띄워보겠습니다.

 

package myapp

import (
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
)

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(res.Code, http.StatusOK)
	data, _ := ioutil.ReadAll(res.Body)
	assert.Equal("hello world", string(data))
}

func TestFooPathHandler_WithoutName(t *testing.T) {
	assert := assert.New(t)
	res := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/foo", nil)
	mux := NewHttpHandler()
	mux.ServeHTTP(res, req)

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

func TestFooPathHandler(t *testing.T) {
	assert := assert.New(t)
	res := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/foo?name=jongyun", nil)
	mux := NewHttpHandler()
	mux.ServeHTTP(res, req)

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

 

 

 

FAIL 이라는 문구와 함께 친절하게 어디서 input 과  output 을 비교해서 알려주네요

 

파이썬을 주 언어로 사용하다가 좀더 빠른 언어가 필요하여 golang 으로 입문하게 되었는데 아직까지 정말 만족하면서 쓰고 있습니다. 마치 c 와 python 을 합쳐놓은 언어 인듯하네요   

728x90

'Go' 카테고리의 다른 글

Go - 삽입정렬 구현하기  (0) 2021.10.03
Go - 구조화된 로그 남기기  (0) 2021.09.24
Go lang 에서 Mysql 연동하기  (0) 2021.09.10
구조체 슬라이스 정렬  (0) 2021.09.07
Go - 스택 메모리와 힙메모리  (0) 2021.09.05