빠른 흐름
bash
go test ./...go
func TestAdd(t *testing.T) {
got := Add(1, 2)
if got != 3 {
t.Fatalf("got %d, want %d", got, 3)
}
}Go 테스트는 별도 프레임워크보다 표준 testing 패키지와 명확한 케이스 목록을 먼저 봅니다.
기본 흐름
테스트 파일은 _test.go로 끝난다
text
calc.go
calc_test.go테스트 함수는 TestXxx(t *testing.T) 형태입니다.
go
func TestParsePort(t *testing.T) {
port, err := ParsePort("8080")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if port != 8080 {
t.Fatalf("got %d, want %d", port, 8080)
}
}t.Fatal과 t.Error는 흐름이 다르다
t.Fatal,t.Fatalf: 실패 후 현재 테스트 중단t.Error,t.Errorf: 실패 기록 후 계속 진행
필수 전제가 깨지면 Fatal, 여러 케이스를 계속 확인하려면 Error가 더 맞습니다.
테이블 테스트
여러 입력/출력을 표로 둔다
Go에서는 같은 함수의 다양한 입력을 struct slice로 두는 table-driven test가 자주 쓰입니다.
go
func TestIsAdult(t *testing.T) {
tests := []struct {
name string
age int
want bool
}{
{name: "minor", age: 19, want: false},
{name: "adult", age: 20, want: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := IsAdult(tt.age)
if got != tt.want {
t.Fatalf("got %v, want %v", got, tt.want)
}
})
}
}t.Run을 쓰면 실패한 케이스 이름이 보이고, 특정 케이스만 골라 실행하기도 쉬워집니다.
helper는 t.Helper()로 표시한다
go
func mustParse(t *testing.T, raw string) int {
t.Helper()
value, err := strconv.Atoi(raw)
if err != nil {
t.Fatalf("parse %q: %v", raw, err)
}
return value
}t.Helper()를 붙이면 실패 위치가 helper 내부가 아니라 호출한 테스트 쪽으로 더 잘 잡힙니다.
선택 기준
| 상황 | 먼저 떠올릴 선택 |
|---|---|
| 패키지 전체 테스트 | go test ./... |
| 필수 전제 실패 | t.Fatal / t.Fatalf |
| 여러 검증을 계속 진행 | t.Error / t.Errorf |
| 입력/출력 조합이 여러 개 | table-driven test |
| 케이스별 이름과 부분 실행 | t.Run |
| 테스트 helper 작성 | t.Helper() |
주의할 점
table-driven test는 케이스가 많을 때 강력하지만, 표가 너무 커지면 무엇을 검증하는지 흐려질 수 있습니다. 같은 실패 원인을 공유하는 케이스끼리 묶고, 경계값과 대표 정상값을 먼저 보이게 두는 편이 읽기 좋습니다.
참고 링크
3 sources