golang에서의 test code는 test할 대상 코드이름이 xxx.go
라면 xxx_test.go
라는 파일로 만든다. 가령 main.go
파일을 test하기위해서 만든 test code는 main_test.go
가 된다.
재밌는 것은 다른 프로그래밍 언어는 test code만 있는 폴더가 따로 있는 반면에 go에서는 test할 코드 바로 옆에 둔다. 가령 다음과 같이 두면 된다.
└── lecture1
├── main.go
└── main_test.go
test할 파일인 main.go
와 test code인 main_test.go
파일, 이들을 한 곳에 묶에 두는 것이 재밌는 특징이다.
다음과 같이 main.go
안에 IsPrime
함수가 있다고 하자. 이를 test하고 싶다면 어떻게 만들어야할까?
func IsPrime(n int) (bool, string) {
if n <= 0 || n == 1 {
return false, "negative value and 0 ,1 is not a prime number\n"
}
for i := 2; i <= n/2; i++ {
if n%i == 0 {
return false, fmt.Sprintf("%d that is not a prime number\n", n)
}
}
return true, fmt.Sprintf("%d that is a prime number\n", n)
}
main_test.go
안에 test code를 쓸 때는 다음과 같이 쓴다.
package main
// or Test_isPrime
func TestIsPrime(t *testing.T) {
}
package
는 테스트할 코드가 있는 package
명과 같거나 _test
접미사로 붙여준다. 가령 test할 package이름이 main
이라면 test code의 package이름도 main
이거나 main_test
로 하는 것이다. 또한, test 함수 이름에는 반드시 대문자로 시작하는 Test 접두사를 붙여야한다. 그리고 그 다음에 나오는 이름은 반드시 대문자가 처음에 나오거나, _로 시작해야한다. 따라서 테스트 함수의 이름 형식은 다음과 같다. TestXxx, Test_xxx 그렇지 않으면 에러가 발생할 것이다.
또한 파라미터로 testing.T
를 받아야하고 리턴값은 없어야 한다. 이것이 기본적인 테스트 함수 모양이다. testing.T
함수를 통해 test에 필요한 기능들을 제공받을 수 있다.
이제 test code를 만들어보자
package main
import "testing"
func TestIsPrime(t *testing.T) {
testValue := 0
result, msg := IsPrime(testValue)
if result {
t.Errorf("with %d as test parameter, got true, but expected false[%s]", testValue, msg)
}
testValue = 7
result, msg = IsPrime(testValue)
if !result {
t.Errorf("with %d as test parameter, got true, but expected false[%s]", testValue, msg)
}
}
실행하려면 test code가 있는 곳에 다음의 명령어를 쳐준다.
go test -v
다음과 같이 t.Errorf
를 사용하면 테스트가 실패한 경우에 로그를 보여준다. 0
의 경우 IsPrime
은 false
이므로 if result
문을 넘어간다. 7
의 경우 IsPrime
은 true
이므로 if !result
문을 넘어간다. 실험으로 if result
문의 !
를 바꿔주면 다음과 같은 로그가 발생한다.,
=== RUN TestIsPrime
main_test.go:9: with 0 as test parameter, got true, but expected false
--- FAIL: TestIsPrime (0.00s)
FAIL
exit status 1
FAIL test-practice 0.001s
기대했던 결과와 실제 값이 달라 에러가 발생하는 것을 확인할 수 있다.
golang test code의 기본에 대해서 정리하자면 다음과 같다.
xxx_test.go
형식으로 만들 것xxx_test.go
파일의 package는 test할 go파일과 같은 package이름이거나 xxx_test
로 지을 것Test
접두사를 가질 것Test
접두사 뒤에는 test할 function 이름을 뒤에 붙일 것, 단 맨 앞 글자는 대문자일 것 ex) ``TextXxx
*testing.T
를 가지고 리턴값은 없을 것golang에서는 기본적으로 test coverage를 알려준다.
go test -cover
결과로 다음과 같다.
PASS
coverage: 83.3% of statements
ok test-practice 0.001s
더 명확하게 어디가 테스팅이 안되었는 지 확인하고 싶다면 test profile
을 만들면 된다.
go test -coverprofile=coverage.out
다음의 명령어로 coverage에 관한 정보를 담은 coverage.out
파일을 만들 수 있다.
mode: set
test-practice/main.go:3.14,5.2 0 0
test-practice/main.go:7.26,8.22 1 1
test-practice/main.go:11.2,11.27 1 1
test-practice/main.go:16.2,16.13 1 1
test-practice/main.go:8.22,10.3 1 1
test-practice/main.go:11.27,12.15 1 1
test-practice/main.go:12.15,14.4 1 0
그러나 이렇게 보기엔 어렵다. 그래서 html파일로 보기좋게 만들도록 하자.
go tool cover -html=coverage.out
html파일이 열리고 어디에 test에 안되었는 지 확인할 수 있다.
html을 파일로 남기고 싶다면 -o
옵션을 같이하면 된다.
go tool cover -html=coverage.out -o cover.html
함수 coverage를 확인하고 싶다면 다음의 명령어를 치면 된다.
go tool cover -func=coverage.out
다음과 같이 각 function에 대한 coverage가 나온다.
test-practice/main.go:3: main 0.0%
test-practice/main.go:7: IsPrime 83.3%
total: (statements) 83.3%