Go Testing

Back to Go Index

Testing Basics

nattrio/go-demo-unit-test

Golang มี Unit test มาให้ใช้ภายในตัวอยู่แล้ว ไม่จำเป็นต้องติดตั้งเพิ่ม

Testing Conventions

Convention ในการเขียน Test มี 3 ข้อ ได้แก่:

  1. The suffix of a filename is _test.go
  2. The name of the unit test function start with Test
  3. The type of a function with 1 parameter is *testing.T
  4. (optional) A package name can have _test as suffix

Running Tests

สามารถรันเทสโดยใช้คำสั่ง go test

  • go test . ใช้รันเทสใน directory นั้น
  • go test ./... ใช้รันเทสใน directory นั้น รวมถึงโฟลเดอร์ย่อย ๆ ทั้งหมด
  • go test -v ใช้รันเทสใน directory นั้น แสดงแบบละเอียด
  • go test -cover ใช้รันเทสใน directory นั้น แล้วบอก % test coverage
  • go test -run="<test_func/subtest>" ใช้รันเฉพาะซับเทส
  • go test -bench=. ใช้ทดสอบ performance
  • go test -tags=integration ใช้รันเทสตาม tag ที่ระบุไว้

Basic Example

ตัวอย่าง cal.go และ cal_test.go

/* cal.go */
func Add(a, b int) int {
	return a + b
}
 
/* cal_test.go */
import "testing"
 
func TestAdd(t *testing.T) {
	r := Add(1, 2)
 
	if r != 3 {
		t.Error("1 + 2 did not equal 3")
	}
}

Package Organization

หมายเหตุ:

  • * (ดอกจัน) หมายถึง pointer แปลว่าเรารับ pointer ของตัวแปรที่มี type เป็น T ซึ่งมาจาก package ชื่อว่า testing
  • เราสามารถวางไฟล์ test กับไฟล์ที่ต้องการ test ไว้ข้างกันหรือใน package ชื่อเดียวกันได้เลย แล้วตั้งชื่อให้ล้อกัน เช่น cal.go กับ cal_test.go

ปกติใน 1 directory จะมี package เดียว แต่ในข้อยกเว้นของการเขียน unit test คือ สามารถแยกไฟล์ test กับไฟล์ที่ต้องการ test ไว้คนละ package ได้ แต่ให้ทำตามเงื่อนไขดังนี้:

  • ชื่อข้างหน้าของ package ต้องเหมือนกัน
  • package ที่เป็น test ให้ต่อท้ายด้วย _test
  • เช่น ใน /services มี cal.go กับ cal_test.go
    • cal.go ใช้ package: services
    • cal_test.go ใช้ package: services_test

VS Code Configuration

Unit Test VS Code Configuration in settings.json

"go.coverOnSave": true,
"go.coverOnSingleTest": true,
"go.coverageDecorator": {
    "type": "gutter",
    "coveredHighlightColor": "rgba(64,128,128,0.5)",
    "uncoveredHighlightColor": "rgba(128,64,64,0.25)",        
    "coveredGutterStyle": "blockgreen",
    "uncoveredGutterStyle": "blockred"
}

Table-Driven Tests

func TestAdd(t *testing.T) {
	tests := []struct {
		name     string
		a, b     int
		expected int
	}{
		{"positive numbers", 1, 2, 3},
		{"negative numbers", -1, -2, -3},
		{"mixed numbers", -1, 2, 1},
	}
 
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := Add(tt.a, tt.b)
			if result != tt.expected {
				t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected)
			}
		})
	}
}

Testing Libraries

package สำหรับ test อื่นๆ เช่น testify

import (
	"testing"
	"github.com/stretchr/testify/assert"
)
 
func TestAdd(t *testing.T) {
	result := Add(1, 2)
	assert.Equal(t, 3, result, "they should be equal")
}

Related: