+1

GOLANG UNIT TESTING VỚI STRETCHR/TESTIFY VÀ MOCKERY

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/testifymockery 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

  1. 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)
    }
    
  2. 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
    }
    
  3. Tạo mocks với mockery
    Bạn có thể tạo mocks cho UserClient với mockery:

    mockery --name=UserClient --output=./mocks
    

    Lệnh này sẽ tạo ra một file mock trong mocks/UserClient.go.

  4. service_test.go
    Bây giờ, chúng ta sẽ viết test cho UserService sử dụng testify assertions và mocked files được tạo trước đó với mockery.

    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

  1. Assertions với testify:
  • Các gói assertrequire đượ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ỗi nil ).
    • 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ị).
  1. Mocking với mockery:
  • mockery tạo ra một mock của interface UserClient .
    • 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.
  1. 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.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí