
시작하며
Go는 언어 자체적으로 테스트와 벤치마킹을 지원한다. go test 명령어 하나로 단위 테스트와 성능 측정을 모두 실행할 수 있으며, 표준 testing 패키지로 테스트 코드를 작성한다. 이 글에서는 테스트 코드 작성 규약, 테스트 주도 개발(TDD), 벤치마크 작성법을 다룬다.
테스트 코드와 벤치마킹
테스트 코드: 작성한 코드를 테스트한다.벤치마크: 작성한 코드의 성능을 확인한다.
테스트 코드 작성 규약
- 파일명이
_test.go로 끝나야 한다. testing패키지를 임포트해야 한다.- 테스트 코드는
func TestXxxx(t *testing.T)형태여야 한다.
테스트 코드 작성 형태
- 테스트 대상이 되는 코드 작성
// test1.go
func square(x int) int {
return x * x
}- 테스트 목적의 프로그램 코드 작성
import "testing"
func TestSquare1(t *testing.T){
rst := square(9)
if rst != 81 {
t.Errorf("square(9) should be 81 but returns %d", rst)
}
}
func TestSquare2(t *testing.T){
rst := square(3)
if rst != 9 {
t.Errorf("square(3) should not be 9 but square(3) returns %d", rst)
}
}- 테스트 코드 실행
# 전체 테스트를 진행하는 경우
go test
# 특정 테스트를 진행하고 싶은 경우는 -run 옵션을 사용한다.
go test -run TestSquare1테스트를 돕는 외부 패키지
go get github.com/stretchr/testify/assert// stretchr/testify/assert
Equal(), Greater(), Len(), NotNilf(), NotEqualf()테스트를 하는 이유
- 프로그램 규모가 커졌다.
- 고가용성이 중요해졌다.
블랙박스 테스트
제품 내부를 공개하지 않은 상태에서 진행하는 테스트이다. 사용자 입장에서 테스트한다고 하여 사용성 테스트라고도 한다. 프로그램 내부를 직접 검증하는 방식이 아닌 프로그램을 실행한 상태로 실행 동작을 검사하는 방식이다. QA 직군에서 주로 담당한다.
화이트박스 테스트
프로그램 코드 내부를 직접 검증하는 방식으로 단위 테스트(unit-test)라고 부른다. 프로그래머가 직접 테스트 코드를 작성해서 내부 테스트를 진행하는 방식이다.
테스트 주도 개발(TDD)
취약점
- 블랙박스 테스트: 코드 내부에 잠재된 버그를 찾기 힘들다.
- 화이트박스 테스트: 사용자 입장에서 전체 서비스를 검사하기 힘들다.
일반적인 테스트 진행 방향은 코드 작성 -> 테스트 후 버그 -> 코드 수정으로 두 가지 문제가 생긴다.
- 테스트 케이스가 빈약해진다.
- 테스트 통과를 목적으로 하는 테스트 코드를 작성할 수 있다.
개발 방식의 변화
테스트 주도 개발(Test Driven Development, TDD)은 테스트 코드 작성 시기를 과감하게 코드 작성 이전으로 옮긴 방식이다.
테스트 코드 작성 -> 테스트 실패 -> 테스트 성공시키는 코드 작성 -> 작성한 코드를 SOLID에 입각한 코드 개선(refactoring) -> 반복
테스트는 많을수록, 촘촘할수록 좋다.
벤치마크
벤치마크 작성 규약
- 파일명이
_test.go로 끝나야 한다. testing패키지를 임포트해야 한다.- 벤치마크 코드는
func BenchmarkXxxx(b *testing.B)형태여야 한다.
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestFibonacci1(t *testing.T) {
assert := assert.New(t)
assert.Equal(0, fibonacci1(-1), "fibonacci(0) should be 0")
assert.Equal(0, fibonacci1(0), "fibonacci(0) should be 0")
assert.Equal(1, fibonacci1(1), "fibonacci(1) should be 1")
assert.Equal(2, fibonacci1(3), "fibonacci(2) should be 2")
assert.Equal(233, fibonacci1(13), "fibonacci(13) should be 233")
}
func TestFibonacci2(t *testing.T) {
assert := assert.New(t)
assert.Equal(0, fibonacci1(-1), "fibonacci(0) should be 0")
assert.Equal(0, fibonacci1(0), "fibonacci(0) should be 0")
assert.Equal(1, fibonacci1(1), "fibonacci(1) should be 1")
assert.Equal(2, fibonacci1(3), "fibonacci(2) should be 2")
assert.Equal(233, fibonacci1(13), "fibonacci(13) should be 233")
}
func BenchmarkFibonacci1(b *testing.B){
for i := 0; i < b.N; i ++ {
fibonacci1(20)
}
}
func BenchmarkFibonacci2(b *testing.B){
for i := 0; i < b.N; i ++ {
fibonacci2(20)
}
}
// goos: darwin
// goarch: amd64
// pkg: GO-STUDY/1_slice/testcode/t2
// cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
// BenchmarkFibonacci1-12 39979 29873 ns/op
// BenchmarkFibonacci2-12 194097885 6.099 ns/op
// PASS
// ok GO-STUDY/1_slice/testcode/t2 3.556s정리하며
Go는 testing 패키지와 go test 명령어만으로 단위 테스트와 벤치마크를 모두 지원한다. TDD는 테스트 코드를 먼저 작성해 코드 품질을 높이고 리팩터링을 안전하게 진행할 수 있게 해준다. testify/assert 외부 패키지를 활용하면 테스트 코드를 더욱 간결하게 작성할 수 있다.