테스트 — RSpec 없이 사는 법
Go의 테스트는 표준 라이브러리에 내장되어 있다. gem install 불필요.
Ruby 테스트 환경을 세팅해본 사람은 안다. RSpec 설치, spec_helper.rb 설정, FactoryBot 세팅, DatabaseCleaner 추가, shoulda-matchers 연결... 처음 테스트 한 줄 돌리기까지 30분은 걸린다.
Go는? _test.go 파일을 만들고 go test를 실행하면 끝이다.
파일 이름이 규칙이다
user.go 파일의 테스트는 user_test.go에 쓴다. _test.go로 끝나는 파일은 go test 실행 시에만 컴파일된다. Ruby의 spec/ 디렉토리 분리 대신 소스 파일 옆에 테스트 파일을 놓는다.
RSpec의 describe/it vs Go의 Test함수
Ruby:
RSpec.describe User do
it "has a name" do
expect(user.name).to eq("kim")
end
end
Go:
func TestUserName(t *testing.T) {
user := User{Name: "kim"}
if user.Name != "kim" {
t.Errorf("expected kim, got %s", user.Name)
}
}
RSpec의 DSL에 익숙하면 Go의 테스트가 원시적으로 보일 수 있다. expect/to 같은 매처(matcher)가 없다. if문으로 직접 비교한다. 이건 Go의 "표준 라이브러리로 충분하다" 철학이다.
테이블 주도 테스트 — Go의 핵심 패턴
Go에서 여러 케이스를 테스트할 때는 struct 슬라이스로 테스트 케이스를 정의한다:
tests := []struct{ input int; want int }{
{1, 2}, {2, 4}, {3, 6},
}
for _, tt := range tests {
got := double(tt.input)
if got != tt.want {
t.Errorf("double(%d) = %d, want %d", tt.input, got, tt.want)
}
}
RSpec의 shared_examples와 비슷한 역할이다.
go test -v, -run, -cover
go test -v — 상세 출력 (RSpec --format documentation 같은 것)
go test -run TestUser — 특정 테스트만 실행 (rspec spec/models/user_spec.rb 같은 것)
go test -cover — 커버리지 확인 (simplecov 같은 것)
별도 gem 설치 없이 전부 내장이다.
Ruby에서 Go로
Ruby: spec/ 디렉토리 + RSpec gem → Go: _test.go 파일 (내장, gem 불필요)
Ruby: describe/it/expect → Go: func TestXxx(t *testing.T) + if + t.Errorf
Ruby: shared_examples → Go: 테이블 주도 테스트 (struct 슬라이스)
Ruby: rspec --format doc → Go: go test -v / -run / -cover (전부 내장)
장점
- ✓ 설정 제로 — gem install, spec_helper, .rspec 파일 전부 불필요
- ✓ go test -cover가 내장 — SimpleCov 없이 커버리지 확인 가능
단점
- ✗ RSpec의 expect().to eq() 같은 가독성 높은 매처가 없다 — if문이 장황
- ✗ FactoryBot 같은 테스트 데이터 생성 도구가 표준에 없다 — 직접 구현 필요