이야기박스

Go Test 간단하게 리뷰 본문

Programming Language

Go Test 간단하게 리뷰

박스님 2022. 2. 10. 20:33
반응형

Go는 자체적인 내장 testing 패키지를 가지고 있습니다. 덕분에 쉽고 빠르게 테스트 코드 작성이 가능한데요. 제목처럼 한번 가볍게 알아보도록 하겠습니다.

 

개요

Go의 테스트 파일은 "_test" 접미사를 달고 있으면 됩니다. 즉, "*_test.go" 형식의 이름을 가지면 되는 거죠.

 

Go의 테스트 패키지는 크게 Example, Benchmark, Test 세 가지 기능이 있습니다. Go에서는 이 기능들을 함수 이름에 접두사로 사용하는 것을 권하고 있습니다. 예를 들어 함수의 이름이 다음과 같아지는 거죠.

Example***, Benchmark***, Test***

 

테스트 실행은 다음과 같은 커맨드로 진행할 수 있습니다.

# 전체 테스트 코드 실행
go test -v ./story

# 특정 테스트 함수 실행
go test -v ./story -run "{{regex}}"

 

그리고 다양한 테스트 옵션을 제공하고 있습니다. 각 옵션은 아래 커맨드를 통하여 자세하게 확인할 수 있습니다.

go help testflag

 

Example

func Example***()

예제 코드를 실행해보고 싶을 때 적절한 함수입니다.

"Output"에 대한 코멘트가 들어가야 원하는 결과를 확인해 볼 수 있습니다.

/**
go test -v ./story -run ^ExampleStory$
*/
func ExampleStory() {
	fmt.Println("story.parks")
	// Output: story.parks
}

 

실행 결과

$ go test -v ./story -run ^ExampleStory$   
=== RUN   ExampleStory
--- PASS: ExampleStory (0.00s)
PASS
ok      _/Users/oringnam/Documents/git/story/go-test/story      0.669s

 

Benchmark

func Benchmark***(b *testing.B)

내가 작성한 함수의 성능이 어떤지 알고 싶을 때, 사용하는 기능입니다. 주로 반복문을 통하여 많이 사용하는 것 같습니다.

/**
go test -v ./story -run ^BenchmarkRandInt$ -bench=. -benchmem -benchtime=5s
*/
func BenchmarkRandInt(b *testing.B) {
	for i := 0; i < b.N; i++ {
		rand.Int()
	}
}

"-benchmem" 옵션은 메모리에 대한 정보도 함께 확인할 때 사용되고, "-benchtime"은 벤치마크를 실행할 시간을 작성합니다.

 

실행 결과

$ go test -v ./story -run ^BenchmarkRandInt$ -bench=. -benchmem -benchtime=5s 
goos: darwin
goarch: amd64
cpu: Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
BenchmarkRandInt
BenchmarkRandInt-16     443546013               13.67 ns/op            0 B/op          0 allocs/op
PASS
ok      _/Users/oringnam/Documents/git/story/go-test/story      7.691s

 

Test

func Test***(t *testing.T)

우리가 생각하는 가장 일반적인 테스트 코드 같습니다.

"Test***" 형태로 시작한 함수는  반환 값을 가지지 않습니다.

 

/**
go test -v ./story -run ^TestSimpleTest$
*/
func TestSimpleTest(t *testing.T) {
	story := "parks"
	if story != "parks" {
		t.Error("Story needs, ", story)
	}

	t.Log("Story has", story)
}

이런 식으로 *testing.T 값에는 로그를 출력할 수 있는 기능이 있고 이는 아래와 같이 나오게 됩니다.

 

실행 결과

$ go test -v ./story -run ^TestSimpleTest$  
=== RUN   TestSimpleTest
    story_test.go:36: Story has parks
--- PASS: TestSimpleTest (0.00s)
PASS
ok      _/Users/oringnam/Documents/git/story/go-test/story      0.424s

 

기타

환경 변수

환경 변수를 받아서 테스트하고 싶은 경우는 어떻게 할까요? 별반 다를 게 없습니다. os 패키지를 이용하고 실행 시 환경변수를 앞에 명시해주면 됩니다.

/**
go test -v ./story -run ^TestEnv$
*/
func TestEnv(t *testing.T) {
	firstName := os.Getenv("FIRST")
	secondName := os.Getenv("SECOND")

	if firstName == "" {
		firstName = "boxx"
	}
	if secondName == "" {
		secondName = "Sstory"
	}

	t.Log("first name is", firstName, ", second name is", secondName)
}
$ FIRST=story SECOND=parks go test -v ./story -run ^TestEnv$
=== RUN   TestEnv
    story_test.go:53: first name is story , second name is parks
--- PASS: TestEnv (0.00s)
PASS
ok      _/Users/oringnam/Documents/git/story/go-test/story      0.254s

 

중복 기능 분리

아무리 테스트 코드라도 중복되는 함수는 밖으로 빼주는 게 좋죠. 테스팅 패키지에서 이용되는 포인터 오브젝트를 넘겨주며 코드를 분리할 수 있습니다.

/**
go test -v ./story -run ^TestDuplication$
*/
func duplicatedCode(t *testing.T) int {
	return rand.Int()
}

func TestDuplication(t *testing.T) {
	t.Log("Pass my testing.T pointer")
	retVal := duplicatedCode(t)

	t.Log("Return Value is ", retVal)
}
$ go test -v ./story -run ^TestDuplication$    
=== RUN   TestDuplication
    story_test.go:64: Pass my testing.T pointer
    story_test.go:67: Return Value is  5577006791947779410
--- PASS: TestDuplication (0.00s)
PASS
ok      _/Users/oringnam/Documents/git/story/go-test/story      0.439s

 

Main

테스트 함수에도 메인 함수가 존재합니다. 위에서는 각 테스트 코드별로 실행 명령어를 주석으로 달아두었는데, 이들을 코드화하여 일괄 실행하고 싶은 경우 사용할 수 있습니다.

/**
go test -v ./story
*/
func TestMain(m *testing.M) {
	fmt.Println("## TestMain Start")

	os.Setenv("FIRST", "story2")
	os.Setenv("SECOND", "parks3")

	exitCode := m.Run()

	fmt.Println("## TestMain End")
	os.Exit(exitCode)
}

 

주로 아래와 같이 모든 테스트 별로 공통된 작업을 먼저 실행해주고 싶을 때, 많이들 사용하는 것 같습니다.

/**
go test -v ./story
*/
func TestMain(m *testing.M) {
	fmt.Println("## TestMain Start")

	testInit()
	exitCode := m.Run()

	fmt.Println("## TestMain End")
	os.Exit(exitCode)
}

func testInit() {
	os.Setenv("FIRST", "story2")
	os.Setenv("SECOND", "parks3")

	fmt.Println("## OS ENV SETTING")
}

 

후기

앞으로는 종종 go에 대한 포스팅도 올리도록 하겠습니다. ㅎㅎ

반응형