zee-solution/docs/testing.md
2025-06-05 21:21:28 +07:00

3.1 KiB

Testing

Tổng quan

Testing là một phần quan trọng trong quy trình phát triển, đảm bảo chất lượng mã nguồn và giảm thiểu bugs. Dự án này sử dụng các công cụ và phương pháp testing tiêu chuẩn trong Golang.

Unit Testing

Công cụ sử dụng

  • Testify: Framework unit testing cho Go
  • Table-driven tests: Thiết kế test cases linh hoạt
  • Mocking: Giả lập dependencies

Quy ước và cấu trúc

  • Mỗi package cần có file *_test.go tương ứng
  • Các test functions có format Test{FunctionName}
  • Test cases nên bao gồm cả happy path và error cases
  • Coverage yêu cầu tối thiểu: 80%
  • Sử dụng t.Run() để chạy các subtest

Mẫu Unit Test

// user_service_test.go
package user

import (
	"testing"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

// Mocking repository
type MockUserRepository struct {
	mock.Mock
}

func (m *MockUserRepository) FindByID(id string) (*User, error) {
	args := m.Called(id)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*User), args.Error(1)
}

func TestGetUser(t *testing.T) {
	// Test cases
	testCases := []struct {
		name          string
		userID        string
		mockUser      *User
		mockError     error
		expectedUser  *User
		expectedError error
	}{
		{
			name:          "successful_get",
			userID:        "123",
			mockUser:      &User{ID: "123", Name: "Test User"},
			mockError:     nil,
			expectedUser:  &User{ID: "123", Name: "Test User"},
			expectedError: nil,
		},
		{
			name:          "user_not_found",
			userID:        "456",
			mockUser:      nil,
			mockError:     ErrUserNotFound,
			expectedUser:  nil,
			expectedError: ErrUserNotFound,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			// Setup mock
			mockRepo := new(MockUserRepository)
			mockRepo.On("FindByID", tc.userID).Return(tc.mockUser, tc.mockError)
			
			// Create service with mock dependency
			service := NewUserService(mockRepo)
			
			// Call the method
			user, err := service.GetUser(tc.userID)
			
			// Assert results
			assert.Equal(t, tc.expectedUser, user)
			assert.Equal(t, tc.expectedError, err)
			
			// Verify expectations
			mockRepo.AssertExpectations(t)
		})
	}
}

Integration Testing

Approach

  • Test containers: Chạy dependent services (database, caching, etc) trong Docker containers
  • API testing: Kiểm tra endpoints và responses
  • DB testing: Kiểm tra queries và migrations

Setup và Teardown

  • Sử dụng TestMain để setup và teardown test environment
  • Cấu hình Docker containers cho testing
  • Cleanup sau khi chạy tests

E2E Testing

  • API black-box testing
  • Sequence testing cho business flows
  • Performance testing

CI/CD Integration

  • Chạy tests trên mỗi commit và PR
  • Lưu test results và coverage
  • Chỉ merge khi tests pass

Best Practices

  1. Write tests first (TDD approach)
  2. Keep tests independent và idempotent
  3. Sử dụng fixtures cho test data
  4. Tránh hard-coding external dependencies
  5. Tách common test code thành helper functions