Skip to content
GwiyeomGo Tech Blog
About GwiyeomGo

TESTCASE golang 으로 테스트케이스 짜기

GOLANG, TESTCASE, 20228 min read

TDD(Test Driven Development)?

‘테스트 주도 개발’을 말한다. 작은 단위로 테스트 케이스를 작성하고 이를 통과하는 코드를 추가하는 단계를 반복하여 구현하는 것

참고

배경

우리는 애자일 기방법론 중 XP 의 Test First 개념을 적용하여 Test Case 를 작성합니다. 이번 글에서는 golang 에서 test case 작성하는 내용을 쓰려고 한다.


1.테스트 케이스를 위한 환경 구성 (테스트 픽스처 설정)

테스트 데이터베이스와 테스트 픽스처 설정 테스트 코드를 실행하기 위해서는 테스트 데이터베이스와 데이터는 테스트 픽스처가 필요합니다. 테스트 픽스텨는 System Under Test를 실행하기 위해 필요한 모든 것을 말합니다.

0.별도 관리가 필요 없는 메모리 데이터베이스 : sqlite SQLite는 MySQL나 PostgreSQL와 같은 데이터베이스 관리 시스템이지만, 서버가 아니라 응용 프로그램에 넣어 사용하는 비교적 가벼운 데이터베이스

이 데이터 베이스를 사용하기 위해서는 3개의 파일을 변경하고 추가해야 합니다.

첫번째 init_test.go 파일을 생성합니다. init_test.go 파일에는 다음 3가지 설정을 합니다. 0.config https://github.com/jinzhu/configor config.InitConfig("config/config.json") 1.echo 프레임 워크 설정 2.DB 엔진 설정 xormEngine = common.InitTest()

init_test.go 전체 코드

//package controllers
import (
"github.com/go-playground/validator/v10"
"github.com/go-xorm/xorm"
"github.com/labstack/echo"
_ "github.com/mattn/go-sqlite3"
"goods-donation-service/common"
"goods-donation-service/config"
)
var (
echoApp *echo.Echo
xormEngine *xorm.Engine
handleWithFilter func(handlerFunc echo.HandlerFunc, c echo.Context) error
)
func init() {
config.InitConfig("config/config.json")
config.Config.Encrypt.GoodsEncryptKey = "+KbPeShVmYq3t6w9z$C&F)J@NcQfTjWn"
xormEngine = common.InitTest()
echoApp = echo.New()
echoApp.Validator = &CustomValidator{validator: validator.New()}
db := common.InitContextDB(xormEngine)
handleWithFilter = func(handlerFunc echo.HandlerFunc, c echo.Context) error {
return db(handlerFunc)(c)
}
}
type CustomValidator struct {
validator *validator.Validate
}
func (cv *CustomValidator) Validate(i interface{}) error {
return cv.validator.Struct(i)
}

두번째 test.go 파일에 sqlite를 사용하겠다고 코드를 추가합니다. comon 디렉토리에 test.go파일에 sqlite를 사용하겠다고 코드를 입력합니다. engine, err := xorm.NewEngine("sqlite3", ":memory:")

test.go 전체 코드

package common
import (
"github.com/go-xorm/xorm"
log "github.com/sirupsen/logrus"
"os"
"runtime"
"xorm.io/core"
)
func InitTest() *xorm.Engine {
runtime.GOMAXPROCS(1)
// Log as JSON instead of the default ASCII formatter.
log.SetFormatter(&log.JSONFormatter{})
// Output to stdout instead of the default stderr
// Can be any io.Writer, see below for File example
log.SetOutput(os.Stdout)
// Only log the warning severity or above.
log.SetLevel(log.InfoLevel)
engine, err := xorm.NewEngine("sqlite3", ":memory:")
if err != nil {
panic(err)
}
engine.ShowSQL(true)
engine.Logger().SetLevel(core.LOG_INFO)
return engine
}

세번째 fixture_test.go 파일을 생성합니다. fixture_test.go 에서는 테스트 코드를 작성할 때 사용할 TABLE을 설정합니다.

xormEngine.Sync2(
new(entities.User),
new(entities.Company),
)

또한 YML에 데이터 TABLE에 추가하는 코드를 설정합니다. fixtures, err := testfixtures.NewFolder(xormEngine.DB().DB, &testfixtures.SQLite, "../testdata/db_fixtures") ../testdata/db_fixtures 경로에 있는 yml 파일을 sqlite DB에 (메모리 DB)에 추가하겠다.

fixture_test.go 전체 코드

package controllers
import (
"fmt"
_ "github.com/mattn/go-sqlite3"
"goods-donation-service/entities"
"gopkg.in/testfixtures.v2"
)
type DatabaseFixture struct {
}
func (DatabaseFixture) setUpDefault() {
xormEngine.Sync2(
new(entities.User),
new(entities.Company),
)
fixtures, err := testfixtures.NewFolder(xormEngine.DB().DB, &testfixtures.SQLite{}, "../testdata/db_fixtures")
fmt.Println("=== RUN DatabaseFixture.setUpDefault")
if err != nil {
panic(err)
}
testfixtures.SkipDatabaseNameCheck(true)
if err := fixtures.Load(); err != nil {
panic(err)
}
fmt.Println("=== FINISH DatabaseFixture.setUpDefault")
}

2.golang 코드로 testcase 작성하기

1. 테스트 케이스 환경 만들기

2. 함수 단위 테스트 케이스 작성

1.controller_test.go 파일 만들기

아래 코드는 controller.go 파일의 내용이다.

func (controller Controller) Init(g *echo.Group) {
g.POST("", controller.Create, middlewares.CheckPermission([]string{"*"}))
g.GET("/:id", controller.Get, middlewares.CheckPermission([]string{"*"}))
}
func (Controller) Create(ctx echo.Context) error {
...
}
  1. Create 함수에 커서를 두고 => goland 의 단축키 Ctrl+Shift+T 동작하면 controller_test.go 파일에 TestController_Create 테스트 케이스를 작성할 수 있는 파일이 생성된다.
func TestController_Create(t *testing.T) {
//go의 경우 test case 를 go 형식의 파일 이름에 쓴다면 작성할 수 있다.
}

2.controller_test.go 파일에 코드 작성

t.Run("CreateWithClassificationByVisit_기부등록", func(t *testing.T) {
//given
requestBody := `{ "name":"수진","meno":"tset"}`
req := httptest.NewRequest(echo.POST,`/`,strings.NewReader(requestBody))
req.Header.Add(echo.HeaderContentType, echo.MIMEApplicationJSON)
userClaim := auth.UserClaim{
Id: 3,
Roles: "manager",
}
// when
rec := NewRequest(req).
WithUser(&userClaim).
Handle(Controller{}.Create)
// then
assert.Equal(t, http.StatusOK, rec.Code)
result := map[string]interface{}{}
json.Unmarshal(rec.Body.Bytes(), &result)
assert.Equal(t, float64(2), result["Id"])
})

golang 테스트 케이스를 작성하면서 주의할 부분

  • 하나의 테스트 실행시 db 설정및 초기화 된다. DatabaseFixture{}.setUpDefault(xormDb)

tip) 여러 케이스를 테스트 하고 싶다면 db 셋팅 후 등록=> 조회까지 한번에 테스트 가능

DatabaseFixture{}.setUpDefault(xormDb)
t.Run("Test_등록_테스트",func(t *testing.T) {//given then when 작성})
t.Run("Test_등록_조회_테스트",func(t *testing.T) {//given then when 작성})
  • t.Skip() 을 통해 전체 테스트 케이스 돌릴때 특정 test case 를 ignored 할 수 있다. 나의 경우는 알림톡이 실제 번호로 전송되는 문제가 있어서 전체 테스트 케이스 실행 시 알림톡이 전송되어 문제가 있었다. 알림톡이 제대로 왔는지 테스트 할때는 t.Skip() 을 주석처리하고 따로 각 테스트 케이스를 돌려서 확인

3.TESTCASE 에 외부 서비스를 호출하는 API 가 존재한다면 어떻게 테스트를 할 수 있을까?

ex) 카카오 알림톡 api 호출하는 코드가 내가 테스트 하려는 코드에 존재할 때

방법1 가상 서버를 생성

httptest 를 사용해서 가상 서버 url 을 생성하고 실제 testcase 에서 api 를 호출할때 url을 가상 서버 url 을 적용합니다.

// setUp WebServer Fixture
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost && r.URL.Path == "/project/434/posts" {
w.WriteHeader(200)
} else {
w.WriteHeader(400)
}
}))
defer server.Close()

방법2 테스트 케이스 실행시 변수를 바꿔 쓴다

#TESTCASE 커버리지 확인하기

배경

테스트 케이스를 적용하면서 잘 적용된 것인지 궁금했다. 실제로 코드의 커버가 얼마나 되는지 확인하는 go 커멘드 명령어를 알아보자

reflect 패키지를 통해

t.Log(reflect.TypeOf("string").Kind()) go test ./... -v

테스트가 코드의 몇 퍼센트를 통과시키고 있는지 알 수 있음 go test -v -coverprofile cover.out ./...

해당 명령어로 cover.out 파일이 생겼다면 cover.out 을 html 파일로 볼 수 있다 go tool cover -html cover.out

go 버전에 따라 명령어가 다른거 같다 아래 명령어로 확인 go tool cover --help

test 환경 config 로 돌리기 configor_env=test go test

service 는 어떻게 테스트하지?

golang 으로 API 를 만들때 testcase 를 작성합니다. controller,service,entidy 별 패키지를 만들어서 API 를 만듭니다. controller 기준 api 를 만들고 있다. service,entitdy 의 함수,스트럭트는 testcase 는 어떻게 할 수 있지?

참고

https://golangdocs.com/code-coverage-in-golang https://ieftimov.com/posts/testing-in-go-go-test/

© 2024 by GwiyeomGo Tech Blog. All rights reserved.