본문 바로가기
Dev/Go

Go에서는 테스트 코드를 어떻게 작성할까

by Sovereign 2024. 8. 5.

테스트 기본 원칙

테스트 코드를 작성할 때 고려하는 많은 원칙들이 있지만 가장 기본적인 2가지 원칙을 선택했다.

Go 테스트 라이브러리 활용 방법에 대해 살펴보기 전에 테스트 작성의 기반이 되는 원칙을 먼저 살펴본 후, 테스트 라이브러리 활용 방법에 대해 코드 레벨로 알아보자.

 

 

 

일곱 테스팅 원칙 (Seven Testing Principles)

1. 테스팅은 결함의 존재를 보여주는 것이다.

  • 테스트의 주요 목적은 제품 내의 결함을 찾아내는 것이며, 결함이 전혀 발견되지 않는다고 해서 소프트웨어에 결함이 없다고 확신할 수 없다.

 

2. 완벽한 테스트는 불가능하다.

  • 모든 가능성(입력과 사전 조건의 모든 조합)을 테스트하는 것은 현실적으로 불가능하다.
  • 따라서, 리스크 기반 접근을 통해 가장 중요한 부분에 테스트를 집중해야 한다.

 

3. 테스트 구성은 가능한 빠르게 시작한다.

 

 

4. 결함은 군집되어 있다.

  • 결함은 보통 소수의 특정 모듈이나 기능에 집중되어 있으며, 이러한 부분이 고장을 초래할 가능성이 높다.

 

5. 살충제 역설(Pesticide Paradox)

  • 동일한 테스트 케이스를 반복적으로 사용하면, 그 테스트 방법으로는 새로운 결함을 발견할 수 없게 된다.

 

6. 테스팅은 문맥에 의존적이다.

  • 테스트는 대상 소프트웨어의 유형, 목적, 사용자에 따라 다르게 접근해야 한다.
  • 예를 들어, 금융 소프트웨어와 게임 소프트웨어는 서로 다른 테스트 전략과 기준을 필요로 합니다.

 

7. 오류 부재의 궤변

  • 소프트웨어가 결함이 없다고 하더라도, 사용자의 요구사항을 충족하지 않거나 사용성이 낮다면 품질이 높다고 할 수 없다.

 

 

 

유닛 테스트

1. 퍼블릭 함수와 메소드를 테스트한다.

 

 

2. 테스트 결과에 영향을 미치는 디펜던시 객체는 모킹한다.

  • 유닛 테스트는 독립적으로 실행되어야 하며, 외부 디펜던시의 영향을 받지 않아야 한다.

 

3. 디스크 관련 디펜던시는 가능한 사용을 피한다.

  • 유닛 테스트에서는 디스크 I/O와 같은 느린 작업을 피해야 한다.
  • 디스크 관련 작업은 테스트를 느리게 만들고, 테스트 환경과 실행 환경 간의 차이를 유발할 수 있다.
  • 가능한 경우, 디스크 의존성을 메모리 기반 접근 방식으로 대체하여 테스트 성능과 일관성을 높이는 것이 좋다.

 

4. 네트워크 관련 디펜던시는 사용하지 않는다.

  • 유닛 테스트에서 네트워크 호출은 지양해야 한다.
  • 네트워크 의존성은 테스트의 속도와 신뢰성을 저하시키며, 네트워크 상태나 외부 서버의 가용성에 따라 테스트 결과가 달라질 수 있다.

 

 

 

테스트 라이브러리

Testify

  • Go에서 테스트 코드 내 Assertions, Mocks, Suite 등의 작업을 더 쉽게 수행할 수 있는 라이브러리다.
  • 다양한 Assertions 메소드를 제공하며, 인터페이스에 대한 모킹 기능과 테스트 Suite 기능을 통해 테스트 코드의 구조화를 지원한다.
go get github.com/stretchr/testify

 

 

Faker

  • Go에서 더미 데이터를 생성하는 데 사용되는 라이브러리다.
  • 다양한 데이터 유형에 대한 랜덤 데이터를 생성할 수 있으며, 구조체에 태그를 사용하여 자동으로 더미 데이터를 채울 수 있다.
go get github.com/bxcodec/faker/v3

 

 

Go SQLMock

  • Go에서 데이터베이스 연동 코드를 테스트하기 위한 라이브러리로, SQL 드라이버를 모킹하여 실제 데이터베이스 없이도 테스트를 수행할 수 있다.
  • SQL 쿼리 모킹, 예상되는 쿼리 및 결과 설정, 트랜잭션 및 오류 처리 등의 작업을 지원한다.
go get github.com/DATA-DOG/go-sqlmock

 

 

 

테스트 파일 및 패키지 이름

  • 파일 이름은 테스트 대상이 되는 go 파일의 이름과 맞춘다.
  • 테스트 대상 패키지에 _test 를 붙여서 테스트를 작성한다. (Blackbox 테스트)
  • 패키지 내부 구현이 복잡할 경우 대상 패키지와 같은 이름을 사용할 수 있다. (Whitebox 테스트)
  • 참조된 객체는 모킹하여 테스트한다.
  대상 테스트
파일 controller.go controller_test.go
패키지 package alert package alert_test (package alert)
함수 GetAlert() Test_GetAlert()

 

 

 

유닛 테스트 작성

테스트 스위트 (TestSuite) 정의

  • Testify 패키지의 suite.Suite 구조체를 포함한 사용자 정의 테스트 스위트를 만들어서, 여러 개의 테스트를 그룹화하고 초기화 및 정리 작업을 쉽게 수행할 수 있다.

  • SetupTest 함수를 통해 테스트 대상과 기타 테스트마다 초기화 되어야 하는 변수들의 초기화를 수행할 수 있고, TearDownTest 함수를 통해 테스트 이후 테스트로 변경된 사항을 정리할 수 있다.

  • 자세한 내용은 Suite Package 문서를 참고하길 바란다.

 

 

모킹 객체를 준비하기

  • 모킹 객체는 mock.Mock 을 활용해서 작성한다. 아래의 예시는 유스케이스 목을 작성하는 예제이다.

  • 구현은 해당 함수를 부르는 쪽에서 응답을 정하도록 작성한다.
    • 테스트 코드에서 함수 호출에 대한 기대되는 결과와 반환값을 사전에 설정한다는 뜻.

 

 

테스트 케이스를 작성하기

  • 테스트 대상(Class)의 모든 공개(Public) 함수들을 테스트 한다.
  • 아래는 위에서 준비한 모킹 객체를 활용해서 컨트롤러 테스트케이스를 작성한 예제이다.

  • 유스케이스의 함수들을 모킹할 때 어떤 함수(GetBy)의 파라미터로 어떤 값(en) 을 전달되어야 하는지를 작성하고 이에 대한 응답도 지정해준다.

 

 

테스트 정의하기

  • 테스트 스위트를 활용해서 테스트할 대상의 함수들에 대해 테스트 작성을 완료 했다면 해당 테스트 스위트를 실행할 테스트 코드를 작성한다.
    • 테스트 코드는 Test 로 시작해야 하며 파라미터로 *testing.T 를 전달한다.

 

 

 

프로젝트 레이아웃 예시

 

컨트롤러

  • api/alertsvc/controller.go
  • 의존성: Alert 도메인의 유스케이스 (Get / Save / Delete)
  • 요청을 적절히 해석하고 유스케이스를 호출하는지 테스트
  • 올바른 HTTP 상태 코드 및 응답을 반환하는지 검증
  • 요청 데이터의 파싱 및 검증 로직을 테스트

 

 

유스케이스

  • alert/usecase.go
  • 의존성: 도메인 내의 entity.go, repository.go
  • 리포지토리와 상호작용하는 로직이 올바르게 구현되었는지 테스트
  • 각 유스케이스가 예상된 입력과 출력으로 동작하는지 확인

 

 

레포지토리

  • alert/repo/repo.go
  • 의존성: datasource/dbalert/source.go

  • SQL 쿼리와 데이터 변환의 정확성을 검증
  • 데이터가 올바르게 저장되고 읽혀지는지 테스트
  • 쿼리의 성능과 결과를 검증

 

 

데이터소스

  • datasource/dbarticle/gorm_source.go
  • 의존성: gorm

  • 데이터베이스 연결 설정의 정확성을 검증
  • 데이터 소스와의 상호작용이 예상대로 수행되는지 테스트
  • 데이터베이스 트랜잭션과 연결 오류 처리 등을 검증

 


출처

Go 테스트 (buzzvil.com)

 

Go 테스트

이 문서는 Go 테스트 방법과 가이드라인을 제공한다. 이는 Go 테스트 추천 라이브러리와 활용 방법에 대한 내용을 포함한다. 단 아래 내용은 추천 사항일 뿐이며, 각 프로젝트에 따라서 언제든 자

tech.buzzvil.com

https://howtodoinjava.com/best-practices/unit-testing-best-practices-junit-reference-guide/

 

Unit Testing Best Practices

Learn to write great unit tests through these top 20 best practices we must consider before writing the test cases. Updated for JUnit 5.

howtodoinjava.com

stretchr/testify: A toolkit with common assertions and mocks that plays nicely with the standard library (github.com)

 

GitHub - stretchr/testify: A toolkit with common assertions and mocks that plays nicely with the standard library

A toolkit with common assertions and mocks that plays nicely with the standard library - stretchr/testify

github.com