기술나눔

단위 테스트 시작

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Go 언어에서 단위 테스트는 단위 테스트를 간단하고 효율적으로 작성, 실행 및 관리할 수 있는 기능 세트를 제공하는 표준 라이브러리의 테스트 패키지를 통해 구현됩니다.

1. 규칙

  • 테스트 파일 명명 규칙
    Go의 테스트 파일 명명 규칙은 다음과 같습니다._test.go .예를 들어,calculator.go 파일, 해당 테스트 파일은 다음과 같아야 합니다.calculator_test.go

  • 테스트 함수의 명명 규칙
    테스트 기능은 다음으로 시작해야 합니다.Test 시작하고 그 뒤에는 비어 있지 않은 문자열이 올 수 있습니다. 예를 들어TestAddTestSubtract 기다리다.

  • 사용 testing.T 주장 및 오류 보고
    테스트 기능에서 다음을 사용하십시오.testing.T 테스트 상태 및 출력을 관리하는 매개변수를 입력합니다.당신이 사용할 수있는t.Error*t.Fail* 테스트 실패를 표시하고 관련 오류 정보를 출력하는 기타 방법.

2. 단위 테스트 예시

2.1 단일 테스트 케이스

계산기 기능은 계산기 패키지에 정의되어 있으며 구체적인 구현은 다음과 같습니다.

package calculator

func Add(a, b int) int {
	return a + b
}
  • 1
  • 2
  • 3
  • 4
  • 5

현재 디렉터리에서 테스트 파일 Calculator_test.go를 생성하고 다음과 같이 테스트 함수를 정의합니다.

package calculator

import "testing"


func TestAdd(t *testing.T) {
	result := Add(1, 2)
	expected := 3
	if result != expected {
		t.Errorf("Add(1,2) return %d, expected %d", result, expected)
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

이 단위 테스트를 실행하려면 go test 명령을 사용하세요.명령줄에 Calculator.go 및 Calculator_test.go가 포함된 디렉터리를 입력한 후 실행합니다.go test, 그 결과는 다음과 같다

go test
PASS
ok      modu    0.226s
  • 1
  • 2
  • 3

2.2 다중 테스트 케이스

Calculator_test.go에 다음 테스트 함수를 추가하세요.

func TestAdd2(t *testing.T) {
	result := Add(3, 2)
	expected := 3
	if result != expected {
		t.Errorf("Add(1,2) return %d, expected %d", result, expected)
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

출력 결과에서 각 테스트 사례의 실행을 더 잘 확인하기 위해 다음을 수행할 수 있습니다.go test -v완전한 테스트 결과를 출력할 수 있는 매개변수입니다.

go test -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
=== RUN   TestAdd2
    calculator_test.go:17: Add(1,2) return 5, expected 3
--- FAIL: TestAdd2 (0.00s)
FAIL
exit status 1
FAIL    modu    0.216s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2.3 실행 중인 테스트 케이스 지정

go test -run 이 명령은 지정된 모드에 따라 테스트를 실행할 수 있습니다. 이 명령은 실행할 테스트 기능을 선택하기 위한 정규식을 지원합니다.

예를 들어 TestAdd2 사용 사례를 수정한 후 다음을 통과합니다.go tes -run=Add2TestAdd2 테스트 케이스만 실행하면 결과는 다음과 같습니다.

go test -run=Add2 -v
=== RUN   TestAdd2
--- PASS: TestAdd2 (0.00s)
PASS
ok      modu    0.198s
  • 1
  • 2
  • 3
  • 4
  • 5

4. 일부 테스트 사례 건너뛰기
새로운 테스트 기능 추가

func TestAdd3(t *testing.T) {
	if testing.Short() {
        t.Skip("short模式下会跳过该测试用例")
    }
	
	result := Add(3, 2)
	expected := 5
	if result != expected {
		t.Errorf("Add(1,2) return %d, expected %d", result, expected)
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

실행할 때go test -short이면 건너뜁니다.testing.Short()표시된 테스트 케이스의 결과는 다음과 같습니다.

go test -short -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
=== RUN   TestAdd2
--- PASS: TestAdd2 (0.00s)
=== RUN   TestAdd3
    calculator_test.go:23: short模式下会跳过该测试用例
--- SKIP: TestAdd3 (0.00s)
PASS
ok      modu    0.635s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3. 테스트 그룹 및 하위 테스트

3.1 테스트 그룹 및 하위 테스트

테스트 그룹 및 하위 테스트를 통해 더 많은 테스트 케이스를 추가하고 결과를 보다 친숙하게 볼 수 있습니다.

func TestAdd(t *testing.T) {
	tests := []struct {
		name     string
		x, y     int
		expected int
	}{
		{"Add1", 1, 2, 3},
		{"Add2", 3, 3, 6},
		{"Add3", 4, 5, 8},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := Add(tc.x, tc.y)
			if result != tc.expected {
				t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)
			}
		})
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

달리다go test -v, 밝혀지다

go test -v
=== RUN   TestAdd
=== RUN   TestAdd/Add2
=== RUN   TestAdd/Add3
    calculator_test.go:51: Add(4, 5) returned 9, expected 8
--- FAIL: TestAdd (0.00s)
    --- PASS: TestAdd/Add1 (0.00s)
    --- PASS: TestAdd/Add2 (0.00s)
    --- FAIL: TestAdd/Add3 (0.00s)
FAIL
exit status 1
FAIL    modu    0.190s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

3.2 병렬 테스트

Go 언어는 본질적으로 동시성을 지원하므로t.Parallel()드라이버 테스트의 병렬화를 달성합니다.

func TestAdd(t *testing.T) {
	t.Parallel()  // 将 TLog 标记为能够与其他测试并行运行
	// 这里使用匿名结构体定义了若干个测试用例
	// 并且为每个测试用例设置了一个名称
	tests := []struct {
		name     string
		x, y     int
		expected int
	}{
		{"Add1", 1, 2, 3},
		{"Add2", 3, 3, 6},
		{"Add3", 4, 5, 8},
	}

	for _, tc := range tests {
		tc := tc  // 注意这里重新声明tt变量(避免多个goroutine中使用了相同的变量)
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()  // 将每个测试用例标记为能够彼此并行运行
			result := Add(tc.x, tc.y)
			if result != tc.expected {
				t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)
			}
		})
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

3.3 테스트 범위

사용go test -cover테스트 범위를 보려면

go test -cover
PASS
        modu    coverage: 100.0% of statements
ok      modu    1.149s
  • 1
  • 2
  • 3
  • 4

4. Go 단위 테스트 툴킷 – 증언

Go 언어로 단위 테스트를 수행할 때 공식 Assertion 기능이 내장되어 있지 않기 때문에 일반적으로 많은 수의 코드를 사용해야 합니다.if...else... 테스트 결과를 확인하기 위한 성명입니다.그러나 다음과 같은 타사 라이브러리를 사용하면testify/assert, 우리는 테스트 코드를 단순화할 뿐만 아니라 명확하고 이해하기 쉬운 오류 설명 정보를 생성하여 문제를 신속하게 찾는 데 도움이 되는 일반적으로 사용되는 다양한 어설션 함수를 쉽게 호출할 수 있습니다.

위의 예에서는if...else...테스트 결과 확인 진술

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := Add(tc.x, tc.y)
			if result != tc.expected {
				t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)
			}
		})
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

지금 이용 가능testify/assert위의 판단 과정은 다음과 같이 단순화됩니다.

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := Add(tc.x, tc.y)
			assert.Equal(t, result, tc.expected)
		})
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

testify/require가지다testify/assert모든 주장 함수들 사이의 유일한 차이점은testify/require실패한 테스트 사례가 발생하면 테스트가 즉시 종료됩니다.