Skip to content

testify

https://github.com/stretchr/testify

https://pkg.go.dev/github.com/stretchr/testify

https://github.com/vektra/mockery

https://blog.csdn.net/darjun/article/details/119658145

https://segmentfault.com/a/1190000040501767

https://segmentfault.com/a/1190000016897506

assert

mock 测试替身

The mock package provides a mechanism for easily writing mock objects that can be used in place of real objects when writing test code.

示例1

1
2
3
$ mkdir testmodule
$ cd testmodule
$ go mod init example.com/testmodule

新建main.go:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package main

type MyInterface interface {
    MyAdd(x, y int) int
}

type MyCal struct{}

func (mycal *MyCal) MyAdd(x, y int) int {
    return x + y
}

func TestCal(calObj MyInterface) {
    calObj.MyAdd(2, 3)
    calObj.MyAdd(333, 333)
}

新建main_test.go:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
    "testing"

    "github.com/stretchr/testify/mock"
)

type MyMockedObject struct {
    mock.Mock
}

func (m *MyMockedObject) MyAdd(x, y int) int {
    args := m.Called(x, y)
    return args.Int(0)
}

func TestSomething(t *testing.T) {
    // create an instance of our test object
    testObj := new(MyMockedObject)
    // setup expectations,这里只设置预期值,不会验证参数和结果的对应关系    
    // 这里只是去测试 TestCal,不会去测试 MyAdd    
    testObj.On("MyAdd", 2, 3).Return(23333)
    testObj.On("MyAdd", 333, 333).Return(66666)
    // call the code we are testing
    TestCal(testObj)
    // assert that the expectations were met
    testObj.AssertExpectations(t)
}
1
2
3
4
5
$ go get github.com/stretchr/testify/mock
$ go test

PASS
ok      example.com/testmodule  0.004s

示例2

我们现在要编写一个从一个站点拉取用户列表信息的程序,拉取完成之后程序显示和分析。
如果每次都去访问网络会带来极大的不确定性,甚至每次返回不同的列表,这就给测试带来了极大的困难。我们可以使用 Mock 技术,让拉取都返回我们指定的结果。

新建main.go:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
)

type User struct {
    Name string
    Age  int
}

type ICrawler interface {
    GetUserList() ([]*User, error)
}

type MyCrawler struct {
    url string
}

func (c *MyCrawler) GetUserList() ([]*User, error) {
    resp, err := http.Get(c.url)
    if err != nil {
        return nil, err
    }

    defer resp.Body.Close()
    data, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    var userList []*User
    err = json.Unmarshal(data, &userList)
    if err != nil {
        return nil, err
    }

    return userList, nil
}

func GetAndPrintUsers(crawler ICrawler) {
    users, err := crawler.GetUserList()
    if err != nil {
        return
    }

    for _, u := range users {
        fmt.Println(u)
    }
}

新建main_test.go:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import (
    "testing"

    "github.com/stretchr/testify/mock"
)

type MockCrawler struct {
    mock.Mock
}

func (m *MockCrawler) GetUserList() ([]*User, error) {
    args := m.Called()
    return args.Get(0).([]*User), args.Error(1)
}

var (
    MockUsers []*User
)

func init() {
    MockUsers = append(MockUsers, &User{"dj", 18})
    MockUsers = append(MockUsers, &User{"zhangsan", 20})
}

func TestGetUserList(t *testing.T) {
    crawler := new(MockCrawler)
    // 每次 GetUserList 都返回 MockUsers,
    // 这里只测试 GetAndPrintUsers 这个函数,不会测试 GetUserList
    // 只是在 GetAndPrintUsers 调用 GetUserList 时返回我们指定的结果   
    crawler.On("GetUserList").Return(MockUsers, nil)

    GetAndPrintUsers(crawler)

    crawler.AssertExpectations(t)
}

suite 测试套件

比较两个结构体

可以使用 reflect 进行比较

1
2
3
if !reflect.DeepEqual(tt.want, got) {
    t.Errorf("prepareData want = %v,\ngot = %v\n", tt.want, got)
}