개요

Unit test는 코드에서 특정 모듈이 정상적으로 동작하는 것을 확인하기 위해 사용된다. 이 때 Unit은 함수가 될 수도 있고 Object가 될 수 도 있고 여러 개의 object로 이루어진 componenet 또한 될 수 있다. 우선 작은 함수 단위에서 테스트를 진행한 후 더 큰 단위의 테스트를 진행하면서 완성된 프로그램을 만들게 된다. (물론 반대로도 가능하다)

Unit test -> Component test -> System test

테스트 한다는 것은 unit이 프로그래머가 의도한 대로 작동하는지 테스트하는 것을 의미한다. 이렇게 Unit test를 사용하면 다음과 같은 이점을 얻을 수 있다. Unit test를 작성하게 되면 자동으로 코드를 검증할 수 있기 때문에 생산성을 향상시킬 수 있고, 프로그래머의 요구에 따라 Unit test가 작성되기에 문서화하는데 도움이 되는 등 여러 장점을 가지게 된다.

Unit test는 활용하면 얻을 수 있는 여러 장점이 생산성 향성을 불러오기 떄문에 다양한 언어들에서 unit test를 위한 여러 툴들을 지원한다. Go 또한 그 언어들 중 하나이다. Go는 자체적으로 test라는 기능을 제공하여 쉽게 unit test를 할 수 있고 여러가지 test를 위한 라이브러리를 제공한다.

테스트할 예제 코드

우선 테스트를 하기 위한 함수를 만들어 보자. 간단하게 덧셈과 뺄셈을 하는 함수를 만들었다. 이해를 위한 코드로 함수 내용은 변경해도 상관없다.

// mymath.go
package main

func myadd(a int, b int) int {
	return a + b
}

func mysub(a int, b int) int {
	return a - b
}

테스트 코드

이제 테스트 하는 코드를 작성해보자. 주의할 점은 go test를 실행하게 되면 _test.go로 끝나는 파일만 테스트하기 때문에 테스트할 파일은 반드시 이름_test.go로 명명해야 한다.

// mytest_test.go
package main

import (
	"testing"
)

func TestTestName(t *testing.T) {
	if myadd(1, 3) != 5 {
		t.Errorf("Test Failed")
	}
}

go에서는 testing라는 테스트를 위한 standard library를 제공한다. 자주 사용하는 함수로는 ErrorfFatalf가 있다. 기능을 간단하게 소개하면 다음과 같다.

Errorf: Log를 실행한 이후 Fail를 실행한다. 포맷 문자열을 출력하고 다음 테스트를 진행하는 것과 같다.
Fatalf: Log를 실행한 이후 FailNow를 실행한다. 포맷 문자열을 출력하고 다음 테스트를 진행하지 않는다.

Log는 Printf와 같고, Fail은 unit을 fail 처리한 후 계속 실행, FailNow는 fail처리한 후 실행을 멈춘다.

테스트가 여러 개일 경우

여러 개의 테스트를 수행하고 싶으면 다음과 같이 하면 된다.

package main

import (
	"testing"
)

func TestTestName(t *testing.T) {
	if myadd(1, 4) != 5 {
		t.Errorf("Test Failed")
	}
	if myadd(3, 4) != 7 {
		t.Errorf("Test Failed")
	}
	if myadd(1, 3) != 5 {
		t.Errorf("Test Failed")
	}
}

그런데 이렇게 할 경우 테스트를 수정하려면 고쳐야 할 코드 부분이 너무 많다. 이럴 땐 구조체 배열을 활용하면 반복된 구문을 줄여 유지보수하기 쉬워진다.

package main

import (
	"testing"
)

func TestMyadd(t *testing.T) {
	tests := []struct {
		param1 		int
		param2		int
		expectedResult 	int
	}{
		{1, 4, 5},
		{3, 4, 7},
		{1, 3, 5},
	}

	for _, test := range tests {
		if myadd(test.param1, test.param2) != test.expectedResult {
			t.Errorf("Test Failed")
		}
	}
}

assert를 활용한 테스트

쉽게 코드를 테스트하기 위해 assert라는 패키지가 존재한다. (사용하기 위해 설치가 필요하다) assert를 사용하면 테스트 코드를 더 직관적이고 깔끔하게 만들어 줄 수 있다.

package main

import (
	"testing"
	"github.com/stretchr/testify/assert"
)

func TestMyadd(t *testing.T) {
	tests := []struct {
		param1 		int
		param2		int
		expectedResult 	int
	}{
		{1, 4, 5},
		{1, 3, 4},
		{1, 3, 5},
	}

	for _, test := range tests {
		assert.Equalf(t, myadd(test.param1, test.param2), test.expectedResult, "Test description")
	}
}

Reference