golang에서는 테스트 코드를 짤 수 있도록 testing
이란 패키지를 지원해 준다.
오늘은 이 testing
패키지를 이용해서 테스트 코드를 짜고 각 함수의 성능을 비교해보는 benchmark까지 다뤄보겠다.
testing
testing
패키지는 고언어의 표준 패키지이기 때문에 따로 받아올 필요가 없다. 그저 testing
패키지를 임포트 해주고 사용하면 된다. 먼저 테스트 코드의 예시를 보겠다.
fibo_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package fibo_test
import (
"testing"
"github.com/j1mmyson/testing/fibo"
)
func TestFibo(t *testing.T) {
ans := fibo.GetFibo(50)
if ans != 12586269025 {
t.Errorf("Fibo(50) = %d; want 12586269025\n", ans)
}
}
Go에서 testing
패키지를 이용할 때는 몇가지 규칙을 지켜야 한다.
- 파일명을
*_test.go
로 지을 것. - 패키지명을
*_test
로 지을 것. - 테스트 함수명을
func TestXxx(t *testing.T)
의 형태로 지을 것. (UpperCamelCase)
테스트 코드를 짜보았다. GetFibo(50)
의 결괏값을 받아와서 그 값이 12586269025
가 아니면 에러를 반환하는 코드이다. 이제 테스트 코드 속에 보이는 GetFibo()
함수를 짜보자. 테스트 코드를 통해 우리가 원하는 GetFibo()
함수의 형태는 정수형 변수를 인자로 받아 정수를 반환해 주는 함수란 것을 알 수 있다.
1
2
3
4
5
6
7
8
9
10
11
package fibo
func GetFibo(n int) int {
n1, n2 := 1, 1
for i := 0; i < n-2; i++ {
n1, n2 = n2, n1+n2
}
return n2
}
GetFibo()
함수도 완성시켰으니 이제 테스트를 시작해보자.
테스트는 테스트 코드가 존재하는 디렉토리에 들어가서 $ go test
명령을 실행시켜주면 된다. 실행시켜보면 아래와 같은 결과를 얻을 수 있다.
1
2
3
$ go test
PASS
ok github.com/j1mmyson/testing/fibo 0.010s
-v
태그를 붙여서 세부사항까지 확인할 수 있다.
1
2
3
4
5
$ go test -v
=== RUN TestFibo
--- PASS: TestFibo (0.00s)
PASS
ok github.com/j1mmyson/testing/fibo 0.009
코드를 잘못 짜 테스트가 실패하면 어떻게 될까? 원하는 출력값이 나오지 않도록 임의로 조정한 후 테스트 코드를 돌리면 아래와 같은 결과를 출력해 준다.
1
2
3
4
5
6
$ go test
--- FAIL: TestFibo (0.00s)
fibo_test.go:13: Fibo(50) = 12586269025; want 1258626902
FAIL
exit status 1
FAIL github.com/j1mmyson/testing/fibo 0.006s
-cover
플래그를 통해 테스트 코드의 coverage
까지 구할 수 있다. coverrage
란 이 프로그램에서 내가 어느 정도까지 테스트 코드를 짰느냐를 나타내는 수치이다. 현재 코드에서 $ go test -cover
를 실행시키면 아래처럼 커버리지가 100%라고 나온다.
1
2
3
4
$ go test -cover
PASS
coverage: 100.0% of statements
ok github.com/j1mmyson/testing/fibo 0.007s
그렇다면 fibo
패키지에 임의의 함수를 하나 추가해보자.
1
2
3
4
5
6
7
8
9
package fibo
import "fmt"
func GetFibo(n int) int {...}
func PrintHello() {
fmt.Println("Hello world!")
}
그러고 다시 테스트 코드를 돌려보면 coverage가 떨어진 것을 확인할 수 있다. PrintHello()
함수에 대한 테스트 코드가 짜여있지 않기 때문이다.
1
2
3
4
$ go test -cover
PASS
coverage: 80.0% of statements
ok github.com/j1mmyson/testing/fibo 0.006s
benchmark
testing
패키지에서는 함수의 성능을 측정할 수 있는 벤치마킹 기능도 제공을 해준다. 앞선 코드에서 n 번 째 피보나치의 수를 구해주는 GetFibo()
함수를 구현했었는데, 조금 다른 방법으로 같은 기능을 구현하는 함수를 하나 더 짜보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func GetFibo(n int) int {
n1, n2 := 1, 1
for i := 0; i < n-2; i++ {
n1, n2 = n2, n1+n2
}
return n2
}
func GetFibo2(n int) int {
var slice []int
slice = []int{1, 1}
for i := 0; i < n-2; i++ {
slice = append(slice, slice[i]+slice[i+1])
}
return slice[len(slice)-1]
}
자, 첫 번째 함수의 경우에는 두 변수를 선언하고 루프를 돌면서 재할당을 반복하는 방식으로 피보나치 수를 구하게끔 구현을 하였고
두 번째 함수에서는 slice를 선언하여 dp 알고리즘으로 슬라이스의 뒤쪽에 계속해서 다음 피보나치 수를 붙여가는 방법을 구현해보았다.
1번 함수의 경우
1
두 변수 선언 + n * (합연산 + 재할당)
2번 함수의 경우
1
슬라이스 선언 + n * (슬라이스에 접근 + 합연산 + 할당) + (중간중간 슬라이스의 용량 늘리기)
과 같은 진행 구조를 가질 것 같다. 이렇게 보면 당연히 1번 함수가 더 빠를 것이라고 예상할 수는 있지만 정확히 얼마나 빠른지 알기는 어려울 것 같다. 이렇게 함수를 구현했으니 벤치마킹 코드도 짜보자.
fibo_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
...
func BenchmarkFibo(b *testing.B) {
for i := 0; i < b.N; i++ {
fibo.GetFibo(50)
}
}
func BenchmarkFibo2(b *testing.B) {
for i := 0; i < b.N; i++ {
fibo.GetFibo2(50)
}
}
각 함수의 인자에 50을 넣은 연산을 testing
패키지에서 제공하는 임의의 수 b.N
만큼 반복을 돌려 함수의 성능을 측정해 준다는 의미이다. 이제 벤치마킹을 진행해보자.
벤치마킹을 해주는 명령은 go test -bench=.
이다. 명령을 실행해보면
1
2
3
4
5
6
7
8
9
$ go test -bench=.
goos: linux
goarch: amd64
pkg: github.com/j1mmyson/testing/fibo
cpu: Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz
BenchmarkFibo-8 60288513 20.00 ns/op
BenchmarkFibo2-8 2552655 885.9 ns/op
PASS
ok github.com/j1mmyson/testing/fibo 4.978s
이렇게 출력을 해준다. 보면 테스트를 돌린 환경이 나오고 중간쯤 보면 BenchmarkFibo-8 ~~~
, BenchmarkFibo2-8 ~~~
부분을 확인할 수 있는데 해당 부분에서 각 함수의 성능을 알 수 있다. 보시다시피 첫 번째 함수의 벤치마킹은 20.00 ns/op
, 두 번째 함수는 885. ns/op
가 나온 것을 확인할 수 있고 이를 보고 확실하게 “아! 이 기능은 첫 번째 함수 방식으로 짜는 게 더 성능이 좋구나!”라고 결론을 내릴 수 있게 되는 것이다.
속도뿐만 아니라 메모리 사용량에 대해서도 벤치마킹해보고 싶다면 아래처럼 명령을 내리면 확인할 수 있다.
1
2
3
4
5
6
7
8
9
$ go test -bench=. -benchmem
goos: linux
goarch: amd64
pkg: github.com/j1mmyson/testing/fibo
cpu: Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz
BenchmarkFibo-8 59181552 19.45 ns/op 0 B/op 0 allocs/op
BenchmarkFibo2-8 2588463 838.1 ns/op 992 B/op 5 allocs/op
PASS
ok github.com/j1mmyson/testing/fibo 4.631s