데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      Go 테스트 코드 작성 및 실행

      sungil 22.02.09
      5,525 7 0

      소프트웨어 개발에서 테스트는 매우 중요하다. 테스트는 여러가지 단계로 나누어 수행되는데 모듈별 테스트로부터 통합테스트까지 다양한 기준점으로 나뉜 테스트들이 개발과정 곳곳에서 수행된다.

      단위 모듈 관점에서 테스트 코드를 넣고 이를 주기적으로 돌리는 방식이 단위 테스트이다. (한국에서) 근 20년동안 가장 사랑받는 언어인 Java에서 사용하는 JUnit과 같은 단위테스트 방법이 가장 유명하고 이러한 테스트를 통한 개발 방법론도 있다. (TDD)

      Go의 영향력이 높아지면서 Go에서도 테스트에 대한 요구들이 나오고 있고 본 페이지를 통해 그 방법을 정리하고자 한다.

      Go 테스트를 위한 기본 지식

      Go에서 시스템적으로 정의하는 테스트 방법은 매우 간단하다. 다음의 규칙을 지켜주면 테스트 된다.

      • Go는 테스트 프레임워크를 내장

      • go test 명령을 통해 테스트

        • *_test.go 에대한 테스트 수행

        • TestXxx 형태의 임의의 매서드에 대해 테스트 진행


      테스트 코드작성

      기본

      작성 규칙은 다음과 같다.

      1. 파일명은 <span style="font-size:16px;">\_test.go</span>로 끝난다.

      2. 함수명은 <span style="font-size:16px;">Test</span>로 시작한다.

      3. 매개변수는 <span style="font-size:16px;">t \*testing.T</span>를 받는다.

      4. 실패지점에서 <span style="font-size:16px;">t.Fail()</span>을 호출한다.


      이를 통해 아래와 같이 작성한다.

      • package는 test

      • testing 모듈 import

      • 함수 작성

        • 입력으로 testing.T를 받고

        • testing.T는 오류함수 제공

          • Fatal() / Error() / Fail() / Log() 등 함수 지원

      package test
      
      import "testing"
      
      func TestFoo(t *testing.T) {
        // todo test code, the variable 'result' should be defined
      	
        expected := 1
        actual := 0
        if result != actual {
          t.Fatal("원하는 결과가 아니네요.")
          // t.Error()
          // t.Fail()
          // t.Log()
        }
      }


      assert 패키지 사용

      기본 test를 하다보면 원하는 조건을 찾기위해 많은 if 문이 발생하는데 이를 깔끔하게 정리하도록 도와주는 것이 assert 패키지 (github.com/stretchr/testify/assert)

      package test
      
      import (
      	"testing"
      	"github.com/stretchr/testify/assert"
      )
      	
      func TestFoo(t *testing.T) {
        // todo test code
        expected := 1
        actual := 0
        assert.Equal(t, expected, actual, "원하는 결과가 아니네요.")
      }

      assert 패키지는 정리된 결과값을 보여준다.

      siim@adm:~/go/src/tks-client/test$ go test 
      --- FAIL: TestFoo (0.00s)
          service_copy_test.go:12: 
                      Error Trace:    service_copy_test.go:12
                      Error:          Not equal: 
                                      expected: 1
                                      actual  : 0
                      Test:           TestFoo
                      Messages:       원하는 결과가 아니네요.
      FAIL
      exit status 1
      FAIL    github.com/openinfradev/tks-client/test 0.005s


      테스트 실행

      • 모든 테스트 실행 $ go test

      • *_test.go 대상으로 테스트 실행하며 상세한 수행내역( -v ) 확인 $ go test *_test.go -v\

      • 특정 테스트 함수(TestFunctionName) 실행 $ go test -run TestFunctionName -v


      테이블 주도 테스트(table-driven test)

      하나의 함수를 테스트하기 위해 여러개의 테스트 케이스가 존재하며 일반적으로 테스트를 작성하면 하나의 테스트 함수는 하나의 테스트 케이스를 수행한다. 이런 경우 테스트 케이스의 숫자와 동일한 테스트 함수가 나오게되고 각 테스트 함수들은 동일 함수에 대한 테스트 이므로 중복된 코드들을 갖게 된다. 이러한 중복을 제거하고자 이를 통합하는 방법으로 테이블 주도 테스트가 이용되고 있다.

      테이블 주도 테스트는 모든 테스트 케이스들을 테이블로 구성하고 하나의 테스트 함수에서 이 테이블을 순회하면서 테스트 한다. 이를 통해 함수 하나당 하나의 테이스 함수를 갖도록 구성할 수 있다.

      이 방식은 여러 Go 언어 커뮤니티에서 권장하는 방식이다.


      테이블의 구조

      테스트 케이스를 구성하고 이에 대한 성공 실패를 판단에 충분한 데이터를 테이들에 포함시키는 것이 중요하다. 따라서 테스트를 위한 객체와 매개변수, 결과, 테스트를 위한 인자 등을 필요에 따라 구성하면 된다.

      다음 예제는 아래와 같은 목적을 수행하기 위해 정의한 구조의 일부이다.

      • 파라미터를 전달 - args

      • 기대하는 출력을 전달 - out, err

      • 불필요한 출력은 비교하지 않는다 - out_check

      testcases := []struct {
      	args      []string
      	out_check bool
      	err       error
      	out       string
      }{
      	{[]string{"wrong"}, true, errors.New("unknown command \\"wrong\\" for \\"tks\\""), ""},
      	{[]string{"wrong", "cmd"}, true, errors.New("unknown command \\"wrong\\" for \\"tks\\""), ""},
      
      	{[]string{"completion", "powershell"}, false, nil, ""},
      
      	{[]string{"--config"}, true, errors.New("flag needs an argument: --config"), ""},
      
      	{[]string{"cluster", "create"}, true, errors.New("required flag(s) \\"contract-id\\", \\"csp-id\\" not set"), ""},
      .........


      테스트 수행

      전체 케이스를 순회하면서 테스트를 진행한다.

      for _, tc := range testcases {
      	out, err := execute(t, rootCmd, tc.args...)
      
      	is.Equal(tc.err, err)
      
      	if tc.err == nil && tc.out_check {
      		is.Equal(tc.out, out)
      	}
      }



      마치며

      본 페이지를 통해 Go에서 개발물에 대한 테스트 코드를 작성하는 방법을 알아보았다. 이 글이 Go test는 정형적인 패턴이 없는 자유로움을 갖고 있고 이로인해 테스트 케이스를 작성하는데 막연함을 갖고 있는 다른분들에게 도움이 되길 바란다. 

      본 내용은 팀에서 개발하고 있는 CLI툴에 대한 테스트를 구성하는 과정에서 알아보았던 내용을 다룬것으로 추가적으로 COBRA라는 CLI용 프레임워크(? 라이브러리?)에서 테스트하는 것을 최종목적으로 하고 있다. 이 내용은 다음 링크에서 확인할 수 있다.

      https://heavenly-part-d73.notion.site/Go-a2c6a5b19ef34a1cadb042c047971a92

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      sungil 님의 최신 블로그

      더보기
      동영상 기고하기