개발바닥

유닛 테스트(Unit Test) 본문

GO 언어

유닛 테스트(Unit Test)

라이언 2022. 3. 9. 19:30
반응형

Go에서 유닛 테스트 작성 방법에 대해 알아보기 전에 유닛 테스트에 대한 개념을 짚고 가겠습니다.

테스트 유형에는 여러 유형이 있지만, 크게 3가지로 단위 테스트, 통합 테스트, 인수 테스트에 대해서 간단하게 알아 보겠습니다.

 

단위 테스트(Unit Test)

단위 테스트는 응용 프로그램에서 테스트 가능한 가장 작은 소프트웨어를 실행하여 예상대로 동작하는지 확인하는 테스트이다. 일반적으로 클래스 또는 메소드 수준으로 정해진다.

 

통합 테스트(Integration Test)

통합 테스트는 단위 테스트보다 더 큰 동작을 달성하기 위해 여러 모듈들을 모아 이들이 의도대로 협력하는지 확인하는 테스트이다. 단위 테스트보다 더 큰 범위로 개발자가 변경할 수 없는 부분(ex 외부 라이브러리)까지 묶어 검증할 떄 사용한다. 즉, 모듈을 통합하는 과정에서 모듈 간의 호환성을 확인하기 위해 수행되는 테스트이다.

 

인수 테스트(Accpetance Test)

인수 테스트는 사용자 스토리(시나리오)에 맞춰 수행하는 테스트이다.

앞선 두 테스트들과 달리 비즈니스 쪽에 초점을 둔다. 다른 의사소통집단(ex 기획자, 디자이너, 개발자 등)으로부터 시나리오를 받아(인수) 개발한다. 시나리오에서 요구하는 것은 "누가, 어떤 목적으로, 무엇으로 하는가" 이다.

 

좋은 단위 테스트 작성 방법

1. 각각의 함수를 단 한가지만의 일을 하도록 작성 (많은 일을 하는 테스팅 코드는 어렵다.)

2. FIRST라는 5가지 규칙을 따른다.

 

FIRST란? Fast, Isolated, Repeatable, Self-validating, Timely 두문자를 따서 "FIRST"라고 한다.
- Fast : 테스트는 빠르게 동작하여 자주 돌릴 수 있어야 하낟.
- Independent : 각각의 테스트는 독립적이며 서로 의존해서는 안된다.
- Repeatable : 어느 환경에서도 반복 가능해야 한다.
- Self-Validating : 테스트는 성공 또는 실패로 bool 값으로 결과를 내어 자체적으로 검증되어야 한다.
- Timely : 테스트는 적시에 즉, 테스트하려는 실젲 코드를 구현하기 직전에 구현해야 한다.

 

Go 유닛 테스트 사용해보기

Go에서는 테스트 프레임워크가 내장되어 있다. 그래서 정해놓은 규칙만 지켜서 사용하기만 하면 바로 테스트를 실행할 수 있다.

 

GO 테스트 작성 규칙

1. 패키지 import : "testing" 패키지 import

2. 파일명 : 파일명_test.go 으로 이름 작성

3. 메소드명 : func Test메소드명(t *testing.T)

 

위 3가지 규칙만 지키면 "go test"라는 명령어를 통해서 테스트 코드들을 실행할 수 있다.

예제 코드를 통해서 간단하게 유닛 테스트를 작성해보겠습니다.

 

// main.go
package main

func Add(a, b int) int {
	return a + b
}
func Sub(a, b int) int {
	return a - b
}

func main() {
}




// main_test.go
package main

import "testing"

type addTest struct {
	arg1, arg2, expected int
}

var addTests = []addTest{
	addTest{2, 3, 5},
	addTest{4, 8, 12},
	addTest{6, 9, 15},
	addTest{3, 10, 13},
}

func TestAdd(t *testing.T) {
	for _, test := range addTests {
		if output := Add(test.arg1, test.arg2); output != test.expected {
			t.Errorf("Output %q not equal to expected %q", output, test.expected)
		}
	}
}

type subTest struct {
	arg1, arg2, expected int
}

var subTests = []subTest{
	subTest{5, 2, 3},
	subTest{10, 12, -2},
	subTest{5, 5, 0},
}

func TestSub(t *testing.T) {
	for _, test := range subTests {
		if output := Sub(test.arg1, test.arg2); output != test.expected {
			t.Errorf("Output %q not equal to expected %q", output, test.expected)
		}
	}
}

코드 설명

main_test.go 파일에 addTests, subTests 타입에 테스트할 데이터를 만든다.

main에 구현한 Add, Sub 함수를 테스트 함수로 만들어서 각 데이터를 테스트한다.

예상 값과 output으로 나온 값이 일치하지 않다면 t.Errorf()함수를 호출해서 실패 로그를 찍는다.

 

이런 식으로 함수 레벨로 테스트를 진행하는 것을 유닛 테스트라고 한다.

 

"testing" 패키징에서 자주 사용하는 함수들 정리

1. t.Errorf(), t.Error()  실패처리하고 로그를 찍을 수 있다.

2. t.Fail() 해당 단계를 실패 처리하고 다음 단계를 계속 진행한다. (로그를 찍을 수 없다.)

3. t.FailNow() 해당 단계를 실패 처리하고 다음 단계를 실행하지 않고 종료한다. (로그를 찍을 수 없다.)

4. t.Log() 테스트 로그를 출력한다.

 

testing 패키지만으로도 충분히 유닛 테스트를 구현할 수 있다.

하지만, 소스 코드를 보다시피 if 문을 남발할 가능성이 높다. 이런 문제점을 해결하기 위해서 "github.com/stretchr/testify" 패키지에 assert를 사용하여 해결할 수 있다.

 

go get github.com/stretchr/testify/assert

 

위 코드를 assert를 적용해 보겠습니다.

//main_test.go
package main

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

type addTest struct {
	arg1, arg2, expected int
}

var addTests = []addTest{
	addTest{2, 3, 5},
	addTest{4, 8, 12},
	addTest{6, 9, 15},
	addTest{3, 10, 13},
}

func TestAdd(t *testing.T) {
	a := assert.New(t)
	for _, test := range addTests {
		a.Equal(test.expected, Add(test.arg1, test.arg2), "they should be equal")
	}
}

type subTest struct {
	arg1, arg2, expected int
}

var subTests = []subTest{
	subTest{5, 2, 3},
	subTest{10, 12, -2},
	subTest{5, 5, 0},
}

func TestSub(t *testing.T) {
	a := assert.New(t)
	for _, test := range subTests {
		a.Equal(test.expected, Sub(test.arg1, test.arg2), "they should be equal")
	}
}

 

코드 설명

if 문 대신에 a.Equal() 함수를 통해서 두 값이 일치하지 않다면 테스트 실패를 발생하게 된다.

 

"github.com/stretchr/testify/assert" 제공하는 함수가 많기 떄문에 https://pkg.go.dev/github.com/stretchr/testify/assert 여기서 적절하게 사용하면 될 거 같다.

 

Go 테스트 작업에 도움되는 라이브러리 

1. gocov

gocov는 테스트에 대한 레포팅 기능을 제공해주는 라이브러리이다. 

// 패키지 추가하기
go get github.com/axw/gocov/gocov
go get github.com/matm/gocov-html

// 실행 커맨드
gocov test ./ > handler.json
gocov-html handler.json > handler.html

테스트 결과 화면

2. goconvey

go test를 하기 위해서 매번 go test 명령으로 확인하기 귀찮고 부담스러울 수 있다.

goconvey는 테스트 코드를 수정할 때마다 수시로 테스트를 통과했는지 실패했는지 확인할 수 있는 패키지이다.

터미널에서 goconvey를 실행시켜서 브라우저에서 실시간으로 테스트를 확인할 수 있다.

 

// 패키지 가져오기
go get github.com/smartystreets/goconvey

// 실행
$GOPATH/bin/goconvey
주의할 점.
goconvey 실행 파일이 $GOPATH/bin에 있는지 확인해야 한다.

아래 이미지처럼 실시간으로 브라우저에서 확인할 수 있다.

 

 

반응형

'GO 언어' 카테고리의 다른 글

[기본 개념 요약] 변수  (0) 2023.03.12
Echo framework로 간단한 웹서버 만들기  (1) 2022.03.27
인터페이스 (interface)  (0) 2022.03.06
모듈(Module)  (0) 2022.03.06
구조체(Struct)  (2) 2022.02.28
Comments