Chúng ta hãy cùng đi qua một ví dụ bao gồm các tính năng phổ biến của thư viện stretchr/testify
và mockery
dùng cho việc mocking trong Golang. Ví dụ này sẽ bao gồm việc testing với assertions, sử dụng gói require
cho các assertions nghiêm ngặt, test HTTP handlers, và mocking các dependencies bằng mockery
.
Kịch bản
Giả sử chúng ta có một service lấy thông tin người dùng từ một API bên ngoài. Chúng ta muốn test những mục sau:
- Chức năng của service.
- Tích hợp của nó với một external client.
- Mocking external client.
Cấu trúc dự án
/project
│
├── main.go
├── service.go
├── service_test.go
├── user_client.go
├── mocks/
│ └── UserClient.go (generated by mockery)
└── go.mod
Tổng quan về source code
-
user_client.go
File này định nghĩa một interface để tương tác với một external user API.package project type User struct { ID int Name string } type UserClient interface { GetUserByID(id int) (*User, error) }
-
service.go
File này chứa một service sử dụng UserClient để lấy thông tin người dùng..package project import "fmt" type UserService struct { client UserClient } func NewUserService(client UserClient) *UserService { return &UserService{client: client} } func (s *UserService) GetUserDetails(id int) (string, error) { user, err := s.client.GetUserByID(id) if err != nil { return "", fmt.Errorf("failed to get user: %w", err) } return fmt.Sprintf("User: %s (ID: %d)", user.Name, user.ID), nil }
-
Tạo mocks với
mockery
Bạn có thể tạo mocks choUserClient
vớimockery
:mockery --name=UserClient --output=./mocks
Lệnh này sẽ tạo ra một file mock trong
mocks/UserClient.go
. -
service_test.go
Bây giờ, chúng ta sẽ viết test choUserService
sử dụngtestify
assertions vàmocked files
được tạo trước đó vớimockery
.package project_test import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/mock" "project" "project/mocks" ) func TestUserService_GetUserDetails_Success(t *testing.T) { // Tạo một mock client mới mockClient := new(mocks.UserClient) // Định nghĩa kết quả mà mock sẽ trả về khi gọi `GetUserByID` mockClient.On("GetUserByID", 1).Return(&project.User{ ID: 1, Name: "John Doe", }, nil) // Tạo UserService với mock client service := project.NewUserService(mockClient) // Test phương thức GetUserDetails result, err := service.GetUserDetails(1) // Sử dụng `require` cho các kiểm tra lỗi require.NoError(t, err) require.NotEmpty(t, result) // Sử dụng `assert` để kiểm tra giá trị kết quả assert.Equal(t, "User: John Doe (ID: 1)", result) // Đảm bảo rằng phương thức `GetUserByID` đã được gọi chính xác một lần mockClient.AssertExpectations(t) } func TestUserService_GetUserDetails_Error(t *testing.T) { // Tạo một mock client mới mockClient := new(mocks.UserClient) // Định nghĩa kết quả mà mock sẽ trả về khi gọi `GetUserByID` và có lỗi xảy ra mockClient.On("GetUserByID", 2).Return(nil, errors.New("user not found")) // Tạo UserService với mock client service := project.NewUserService(mockClient) // Test phương thức GetUserDetails result, err := service.GetUserDetails(2) // Sử dụng `require` cho các kiểm tra lỗi require.Error(t, err) assert.Contains(t, err.Error(), "user not found") // Đảm bảo rằng kết quả là rỗng assert.Empty(t, result) // Đảm bảo rằng phương thức `GetUserByID` đã được gọi chính xác một lần mockClient.AssertExpectations(t) }
Những điểm chính của ví dụ trên
- Assertions với
testify
:
- Các gói
assert
vàrequire
được sử dụng cho các kiểu kiểm tra khác nhau.require
được sử dụng cho các test case cần dừng bài test ngay lập tức nếu thất bại (ví dụ: kiểm tra lỗinil
).assert
được sử dụng cho các test case có thể tiếp tục ngay cả khi chúng fail (ví dụ: so sánh giá trị).
- Mocking với
mockery
:
mockery
tạo ra một mock của interfaceUserClient
.- Trong bài test, mock được cấu hình bằng
.On()
để chỉ định input mong muốn và.Return()
để chỉ định output tương ứng. AssertExpectations
xác minh rằng phương thức mock đã được gọi với expected inputs.
- Trong bài test, mock được cấu hình bằng
- Testing và xử lý lỗi:
- Một bài test kiểm tra trường hợp success, trong khi bài còn lại kiểm tra cách service xử lý lỗi từ
UserClient
.
Cài đặt trên khái quát các chức năng cơ bản của stretchr/testify
cho assertions và mocking với mockery
, cung cấp một cách tiếp cận có cấu trúc và dễ bảo trì cho unit tests trong Golang. Cảm ơn bạn đã xem hết.