[unit-testing] Go에서 테스트 패키지를 사용하여 테스트 설정을 수행하려면 어떻게해야합니까?

테스트 패키지를 사용할 때 모든 테스트의 단계를 설정하는 전체 테스트 설정 처리를 어떻게 할 수 있습니까?

Nunit의 예로서 [SetUp]속성이 있습니다.

[TestFixture]
public class SuccessTests
{
  [SetUp] public void Init()
  { /* Load test data */ }
}



답변

Go 1.4부터는 설정 / 해체를 구현할 수 있습니다 (각 테스트 전후에 함수를 복사 할 필요 없음). 설명서는 여기 기본 섹션 에 요약되어 있습니다 .

TestMain은 메인 고 루틴에서 실행되며 m.Run 호출과 관련하여 필요한 모든 설정 및 해체를 수행 할 수 있습니다. 그런 다음 m.Run의 결과로 os.Exit를 호출해야합니다.

테스트에 함수가 포함되어 있으면 테스트 func TestMain(m *testing.M)를 실행하는 대신이 함수가 호출 된다는 것을 알아내는 데 시간이 좀 걸렸습니다 . 이 함수에서 테스트 실행 방법을 정의 할 수 있습니다. 예를 들어 전역 설정 및 해체를 구현할 수 있습니다.

func TestMain(m *testing.M) {
    setup()
    code := m.Run()
    shutdown()
    os.Exit(code)
}

여기에서 몇 가지 다른 예 를 찾을 수 있습니다 .

최신 릴리스에서 Go의 테스트 프레임 워크에 추가 된 TestMain 기능은 여러 테스트 사용 사례를위한 간단한 솔루션입니다. TestMain은 설정 및 종료를 수행하고, 테스트 환경을 제어하고, 자식 프로세스에서 다른 코드를 실행하거나, 테스트 코드에서 유출 된 리소스를 확인하기위한 전역 후크를 제공합니다. 대부분의 패키지에는 TestMain이 필요하지 않지만 필요할 때 추가 할 수 있습니다.


답변

이것은 파일에 init()함수를 넣어서 얻을 수 있습니다 _test.go. 이것은 init()함수 전에 실행 됩니다.

// package_test.go
package main

func init() {
     /* load test data */
}

_test.init ()는 패키지 init () 함수보다 먼저 호출됩니다.


답변

단위 테스트에 대한 간단한 함수가 주어지면 :

package math

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

분해 기능을 반환하는 설정 기능으로 테스트 할 수 있습니다. 그리고 setup ()을 호출 한 후 teardown ()을 지연 호출 할 수 있습니다.

package math

import "testing"

func setupTestCase(t *testing.T) func(t *testing.T) {
    t.Log("setup test case")
    return func(t *testing.T) {
        t.Log("teardown test case")
    }
}

func setupSubTest(t *testing.T) func(t *testing.T) {
    t.Log("setup sub test")
    return func(t *testing.T) {
        t.Log("teardown sub test")
    }
}

func TestAddition(t *testing.T) {
    cases := []struct {
        name     string
        a        int
        b        int
        expected int
    }{
        {"add", 2, 2, 4},
        {"minus", 0, -2, -2},
        {"zero", 0, 0, 0},
    }

    teardownTestCase := setupTestCase(t)
    defer teardownTestCase(t)

    for _, tc := range cases {
        t.Run(tc.name, func(t *testing.T) {
            teardownSubTest := setupSubTest(t)
            defer teardownSubTest(t)

            result := Sum(tc.a, tc.b)
            if result != tc.expected {
                t.Fatalf("expected sum %v, but got %v", tc.expected, result)
            }
        })
    }
}

Go 테스트 도구는 셸 콘솔에 로깅 문을보고합니다.

% go test -v
=== RUN   TestAddition
=== RUN   TestAddition/add
=== RUN   TestAddition/minus
=== RUN   TestAddition/zero
--- PASS: TestAddition (0.00s)
    math_test.go:6: setup test case
    --- PASS: TestAddition/add (0.00s)
        math_test.go:13: setup sub test
        math_test.go:15: teardown sub test
    --- PASS: TestAddition/minus (0.00s)
        math_test.go:13: setup sub test
        math_test.go:15: teardown sub test
    --- PASS: TestAddition/zero (0.00s)
        math_test.go:13: setup sub test
        math_test.go:15: teardown sub test
    math_test.go:8: teardown test case
PASS
ok      github.com/kare/go-unit-test-setup-teardown 0.010s
% 

이 접근 방식을 사용하여 설정 / 해체에 몇 가지 추가 매개 변수를 전달할 수 있습니다.


답변

일반적으로 이동중인 테스트는 다른 언어와 동일한 스타일로 작성되지 않습니다. 종종 비교적 적은 수의 테스트 함수가 있지만 각각에는 테이블 기반 테스트 사례 집합이 포함됩니다. Go 팀 중 한 사람이 작성한이 기사를 참조하십시오 .

테이블 기반 테스트에서는 테이블에 지정된 개별 테스트 케이스를 실행하는 루프 앞에 설정 코드를 넣고 나중에 정리 코드를 넣으면됩니다.

테스트 함수간에 설정 코드를 공유하고있는 경우 공유 설정 코드를 함수로 추출하고 sync.Once정확히 한 번 실행하는 것이 중요한 경우 a를 사용할 수 있습니다 (또는 다른 답변에서 알 수 있듯이을 사용 init()하지만 설정이 단점이 있습니다. 테스트 케이스가 실행되지 않은 경우에도 수행됩니다 (를 사용하여 테스트 케이스를 제한했기 때문일 수 있습니다 go test -run <regexp>.)

정확히 한 번 실행되는 서로 다른 테스트간에 공유 설정이 필요하다고 생각한다면 실제로 필요한지, 테이블 기반 테스트가 더 좋지 않을지 생각 해봐야합니다.


답변

Go 테스트 프레임 워크에는 NUnit의 SetUp 속성 (스위트의 각 테스트 전에 호출 할 함수 표시)에 해당하는 것이 없습니다 . 하지만 몇 가지 옵션이 있습니다.

  1. SetUp필요한 곳에서 각 테스트에서 함수를 호출하기 만하면 됩니다.

  2. xUnit 패러다임과 개념을 구현하는 Go의 테스트 프레임 워크 확장을 사용합니다. 세 가지 강력한 옵션이 떠 오릅니다.

이러한 각 라이브러리는 테스트를 다른 xUnit 프레임 워크와 유사한 스위트 / 픽스처로 구성하도록 권장하고 각 메소드 이전에 스위트 / 픽스처 유형에 대한 설정 메소드를 호출합니다 Test*.


답변

이 문제를 정확히 해결하기 위해 뻔뻔한 플러그, https://github.com/houqp/gtest 를 만들었습니다 .

다음은 간단한 예입니다.

import (
  "strings"
  "testing"
  "github.com/houqp/gtest"
)

type SampleTests struct{}

// Setup and Teardown are invoked per test group run
func (s *SampleTests) Setup(t *testing.T)      {}
func (s *SampleTests) Teardown(t *testing.T)   {}
// BeforeEach and AfterEach are invoked per test run
func (s *SampleTests) BeforeEach(t *testing.T) {}
func (s *SampleTests) AfterEach(t *testing.T)  {}

func (s *SampleTests) SubTestCompare(t *testing.T) {
  if 1 != 1 {
    t.FailNow()
  }
}

func (s *SampleTests) SubTestCheckPrefix(t *testing.T) {
  if !strings.HasPrefix("abc", "ab") {
    t.FailNow()
  }
}

func TestSampleTests(t *testing.T) {
  gtest.RunSubTests(t, &SampleTests{})
}

각기 다른 설정 / 해체 루틴을 사용하여 패키지 내에서 원하는 테스트 그룹을 만들 수 있습니다.


답변