網頁

2021/7/14

Golang Testify mock簡單範例二

Go測試套件Testify mock使用範例。


範例環境:

  • Go 1.18
  • Testify 1.7.0

範例專案的module名稱為abc.com/demo


主程式

以下為主程式的函式、型別及檔案。

model/employee.go定義一個Employee struct型別,為其他函式中使用的參數。

model/employee.go

package model

type Employee struct {
    ID   int64
    Name string
    Age  int
}

service/employee_service.go中定義了EmployeeService介面提供取得資深員工數目的方法GetSrEmployeeNumbers()與介面的實作型別EmployeeSerivceImplEmployeeSerivceImpl.GetSrEmployeeNumbers()委託其依賴repo.EmployeeRepo查詢大於特定年紀的員工。

service/employee_service.go

package serivce

import "abc.com/demo/repo"

type EmployeeService interface {
    GetSrEmployeeNumbers() int
}

type EmployeeSerivceImpl struct {
    EmpRepo repo.EmployeeRepo
}

func (es *EmployeeSerivceImpl) GetSrEmployeeNumbers(age int) int {
    srEmps := es.EmpRepo.FindEmployeesAgeGreaterThan(age)
    return len(srEmps)
}

repo/employee_repo.go中定義了EmployeeRepo介面提供查詢大於某年紀的員工的方法FindEmployeesAgeGreaterThan()與介面的實作型別EmployeeRepoImplEmployeeRepoImpl.FindEmployeesAgeGreaterThan()模擬從資料庫取得員工。

repo/employee_repo.go

package repo

import (
    "sort"

    "abc.com/demo/model"
)

type EmployeeRepo interface {
    FindEmployeesAgeGreaterThan(age int) []model.Employee
}

type EmployeeRepoImpl struct {
}

func (er *EmployeeRepoImpl) FindEmployeesAgeGreaterThan(age int) []model.Employee {
    m := map[int]model.Employee{
        1: {ID: 1, Name: "John", Age: 33},
        2: {ID: 2, Name: "Mary", Age: 21},
        3: {ID: 3, Name: "Mike", Age: 45},
    }
    emps := []model.Employee{}
    for _, emp := range m {
        if emp.Age > age {
            emps = append(emps, emp)
        }
    }
    sort.Slice(emps, func(i, j int) bool {
        return emps[i].Age < emps[j].Age // sort by Age asc
    })
    return emps
}


測試程式

employee_service_test.goemployee_service.go的測試程式並使用Testify的mock.Mock來取代被測對象的中的依賴,並利用mock.On()設計呼叫mock方法的預期的輸入參數及回傳值。

service/employee_service_test.go

package serivce

import (
    "testing"

    "abc.com/demo/model"
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/mock"
)

// define mock type
type EmployeeRepoImplMock struct {
    mock.Mock
}

// use mock to implments EmployeeRepo's method
func (repoMock *EmployeeRepoImplMock) FindEmployeesAgeGreaterThan(age int) []model.Employee {
    args := repoMock.Called(age)
    return args.Get(0).([]model.Employee)
}

func TestGetSrEmployeeNumbers_Age40(t *testing.T) {

    repoMock := new(EmployeeRepoImplMock)
    repoMock.On("FindEmployeesAgeGreaterThan", 40).
        Return([]model.Employee{
            {ID: 99, Name: "Jack", Age: 70}, // mock return value
        })

    expected := 1

    es := EmployeeSerivceImpl{
        EmpRepo: repoMock,
    }

    actial := es.GetSrEmployeeNumbers(40)
    assert.Equal(t, expected, actial)
}

employee_repo_test.goemployee_repo.go的測試程式。

repo/employee_repo_test.go

package repo

import (
    "testing"

    "abc.com/demo/model"
    "github.com/stretchr/testify/assert"
)

func TestFindEmployeesAgeGreaterThan30(t *testing.T) {
    testCase := struct {
        age      int
        expected []model.Employee
    }{
        30,
        []model.Employee{
            {ID: 1, Name: "John", Age: 33},
            {ID: 3, Name: "Mike", Age: 45},
        },
    }

    empRepo := EmployeeRepoImpl{}
    actial := empRepo.FindEmployeesAgeGreaterThan(30)

    assert.Equal(t, testCase.expected, actial)
}

執行測試

在專案根目錄以命令列輸入go test -v ./...執行根目錄下所有子目錄中的測試程式。

$ go test -v ./...
?       abc.com/demo    [no test files]
?       abc.com/demo/model      [no test files]
=== RUN   TestFindEmployeesAgeGreaterThan30
--- PASS: TestFindEmployeesAgeGreaterThan30 (0.00s)
PASS
ok      abc.com/demo/repo       0.599s
=== RUN   TestGetSrEmployeeNumbers_Age40
--- PASS: TestGetSrEmployeeNumbers_Age40 (0.00s)
PASS
ok      abc.com/demo/serivce    0.326s

github


沒有留言:

張貼留言