網頁

2021/7/13

Golang Testify mock簡單範例

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


範例環境:

  • Go 1.16
  • Testify 1.7

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


主程式

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

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

model/employee.go

package model

type Employee struct {
    Id   int
    Name string
    Age  int
}

service/calculator.go中定義了CalculatorService介面供計算整數加減的方法Plus()Minus()與介面的實作型別Calculator。為下面測試程式要mock的對象。

service/calculator.go

package serivce

type CalculatorService interface {
    Plus(int, int) int
    Minus(int, int) int
}

type Calculator struct {
}

func (c Calculator) Plus(x, y int) int {
    return x + y
}

func (c Calculator) Minus(x, y int) int {
    return x - y
}

main.go的兩個函式AddAge()AgeDiff()用來計算員工年齡相關邏輯,兩函式皆依賴CalculatorService介面提供的計算方法。兩函式為下面main_test.go測試程式要測試的對象

main.go

package main

import (
    "errors"

    "abc.com/demo/model"
    "abc.com/demo/serivce"
)

func AddAge(x int, emp model.Employee, calService serivce.CalculatorService) (int, error) {
    if (emp == model.Employee{}) {
        return -1, errors.New("emp is empty")
    }
    return calService.Plus(x, emp.Age), nil
}

func AgeDiff(emp1, emp2 model.Employee, calService serivce.CalculatorService) (int, error) {
    if (emp1 == model.Employee{}) || (emp2 == model.Employee{}) {
        return 0, errors.New("one emp is empty")
    }
    return calService.Minus(emp1.Age, emp2.Age), nil
}


測試程式

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

main_test.go

package main

import (
    "testing"

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

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

// use mock to implments CalculatorService's method
func (calMock *CalculatorMock) Plus(x, y int) int {
    args := calMock.Called(x, y)
    return args.Int(0)
}

func (calMock *CalculatorMock) Minus(x, y int) int {
    args := calMock.Called(x, y)
    return args.Int(0)
}

func TestAddAge(t *testing.T) {

    calMock := new(CalculatorMock)       // create mock instance
    calMock.On("Plus", 1, 33).Return(34) // setup mock method arguments and return value

    testCase := struct {
        x        int
        emp      model.Employee
        expected int
    }{
        1,
        model.Employee{Id: 1, Name: "John", Age: 33},
        34,
    }

    actual, _ := AddAge(testCase.x, testCase.emp, calMock) // pass test arguments and mock to replace real one

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

func TestAgeDiff(t *testing.T) {

    calMock := new(CalculatorMock)
    calMock.On("Minus", 33, 23).Return(10)

    testCase := struct {
        emp1     model.Employee
        emp2     model.Employee
        expected int
    }{
        model.Employee{Id: 1, Name: "John", Age: 33},
        model.Employee{Id: 2, Name: "Mary", Age: 23},
        10,
    }

    actual, _ := AgeDiff(testCase.emp1, testCase.emp2, calMock)

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

要能mock依賴方法的重點在於,依賴方法須為介面方法如此才能在測試程式中以mock實作來替代。


執行測試

在專案根目錄以命令列輸入go test -v執行測試。

$ go test -v
=== RUN   TestAddAge
--- PASS: TestAddAge (0.00s)
=== RUN   TestAgeDiff
--- PASS: TestAgeDiff (0.00s)
PASS
ok      abc.com/demo    0.335s

參考github


沒有留言:

張貼留言