숏컷 코드
func TestLoadConfig(t *testing.T) {
dir := t.TempDir()
t.Setenv("APP_CONFIG_DIR", dir)
writeFile(t, filepath.Join(dir, "config.json"), `{"debug":true}`)
cfg, err := LoadConfig()
if err != nil {
t.Fatal(err)
}
if !cfg.Debug {
t.Fatal("Debug = false")
}
}
func writeFile(t *testing.T, path, body string) {
t.Helper()
if err := os.WriteFile(path, []byte(body), 0o600); err != nil {
t.Fatal(err)
}
}fixture 흐름
Cleanup은 테스트가 끝날 때 정리 작업을 등록한다
t.Cleanup은 테스트가 끝난 뒤 실행할 함수를 등록합니다. 파일, 서버, mock 상태, 전역 변수 복원처럼 테스트 중간에 실패해도 정리되어야 하는 작업에 적합합니다.
func TestServer(t *testing.T) {
srv := httptest.NewServer(handler())
t.Cleanup(srv.Close)
res, err := http.Get(srv.URL)
if err != nil {
t.Fatal(err)
}
defer res.Body.Close()
}defer도 함수 종료 시 실행되지만, helper 함수 안에서 fixture를 만들 때는 t.Cleanup이 더 자연스럽습니다. helper가 반환된 뒤에도 테스트가 끝날 때까지 자원을 유지하고, 종료 시점에 정리할 수 있기 때문입니다.
TempDir은 테스트 전용 디렉터리를 만들고 자동 삭제한다
t.TempDir()은 테스트별 임시 디렉터리를 만들고 테스트와 하위 테스트가 끝난 뒤 삭제합니다. 파일 시스템을 사용하는 테스트에서 OS 전역 temp 경로를 직접 조합하는 것보다 충돌과 정리 누락이 적습니다.
func TestExport(t *testing.T) {
dir := t.TempDir()
out := filepath.Join(dir, "report.txt")
if err := Export(out); err != nil {
t.Fatal(err)
}
}테스트 결과를 디버깅하려고 임시 파일을 남겨야 하는 경우가 아니라면 TempDir을 기본값으로 두는 편이 좋습니다.
Helper는 실패 위치를 테스트 호출부로 올려 준다
테스트 helper 안에서 t.Fatal이나 t.Errorf를 호출하면 기본적으로 helper 함수 내부 줄이 실패 위치로 보일 수 있습니다. t.Helper()를 호출하면 실패 출력에서 helper 함수 프레임을 건너뛰어 실제 테스트 호출부가 더 잘 보입니다.
func mustRead(t *testing.T, path string) string {
t.Helper()
b, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
return string(b)
}테스트마다 반복되는 검증, 파일 생성, JSON 비교 helper에는 첫 줄에 t.Helper()를 넣는 것이 좋습니다.
Setenv는 환경 변수 복원을 Cleanup으로 처리한다
t.Setenv는 환경 변수를 설정하고 테스트가 끝난 뒤 원래 값으로 복원합니다. 환경 변수를 직접 os.Setenv로 바꾸면 실패 경로에서 복원을 놓치기 쉽습니다.
func TestMode(t *testing.T) {
t.Setenv("APP_MODE", "test")
if got := Mode(); got != "test" {
t.Fatalf("Mode() = %q", got)
}
}환경 변수는 프로세스 전체 상태이므로 parallel test와 함께 쓸 때 주의해야 합니다. 같은 프로세스의 다른 테스트가 같은 환경 변수를 읽을 수 있기 때문입니다.
선택 기준
| 상황 | 적합한 선택 |
|---|---|
| 테스트 종료 시 자원 정리 | t.Cleanup |
| 임시 파일이나 디렉터리 필요 | t.TempDir |
| helper 실패 위치를 호출부로 표시 | t.Helper |
| 환경 변수 변경과 복원 | t.Setenv |
| 전역 상태를 병렬 테스트에서 변경 | 병렬화 피하거나 상태 분리 |
fixture는 테스트 본문을 짧게 만드는 수단입니다. 다만 helper가 많은 일을 숨기면 테스트 실패 원인을 읽기 어려워지므로, 입력 준비와 검증 helper는 이름을 구체적으로 두는 편이 좋습니다.
주의할 점
환경 변수, 현재 작업 디렉터리, 전역 logger 같은 프로세스 전역 상태는 병렬 테스트에서 충돌할 수 있습니다.
t.Cleanup이 복원해 주더라도 동시에 실행되는 다른 테스트가 중간 상태를 볼 수 있습니다.
func TestA(t *testing.T) {
t.Parallel()
t.Setenv("APP_MODE", "a") // 병렬 테스트와 함께 쓰면 위험
}helper 안에서 goroutine을 만들고 그 goroutine에서 t.Fatal을 호출하면 테스트 goroutine을 멈추지 못합니다. goroutine 결과는 channel이나 error 값으로 모아 테스트 goroutine에서 판정하는 편이 안전합니다.
참고 링크
1 sources