logo头像
Snippet 博客主题

Table Driven Tests For Golang

本文于330天之前发表,文中内容可能已经过时。

Table Driven Tests - best practice

  1. VSCode Golang plugin Go: Generate Unit Tests for Function
  2. Goland plugin

hello.go

exmaple

1
2
3
func hello(ctx context.Context, name string) (string, error) {
return fmt.Sprintf("hello %s", name), nil
}

hello_test.go

generate by VSCode

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
func Test_hello(t *testing.T) {
type args struct {
ctx context.Context
name string
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := hello(tt.args.ctx, tt.args.name)
if (err != nil) != tt.wantErr {
t.Errorf("hello() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("hello() = %v, want %v", got, tt.want)
}
})
}
}

hello_test.go

Manually update version1

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
54
55
56
func Test_hello(t *testing.T) {
// one of the external client calling
var auditLogMock *mocks.ILogClient

type args struct {
ctx context.Context
name string
}
tests := []struct {
name string
args args
want string
wantErr bool
origin []interface{}
setupMocks func()
verifyMocks func()
}{
{
name: "happy path",
args: args{
ctx: context.Background(),
name: "wdxxl",
},
want: "hello wdxxl",
wantErr: false,
origin: []interface{}{external.AuditLogClient},
setupMocks: func() {
// mock interface
auditLogMock = &mocks.ILogClient{}
auditLogMock.On("AsyncSendAuditLog", mock.Anything, mock.Anything)
external.AuditLogClient = auditLogMock
},
verifyMocks: func() {
// verify the interface been called or not
auditLogMock.AssertNumberOfCalls(t, "AsyncSendAuditLog", 1)
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// golang unit test setup & restore individual
defer testtools.Restore(testtools.Pairs(tt.origin...)...)
tt.setupMocks()
defer tt.verifyMocks()

got, err := hello(tt.args.ctx, tt.args.name)
if (err != nil) != tt.wantErr {
t.Errorf("hello() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("hello() = %v, want %v", got, tt.want)
}
})
}
}

hello_test.go

Manually update version2

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
54
55
56
57
58
59
60
func Test_hello(t *testing.T) {
// one of the external client calling
var auditLogMock *mocks.ILogClient

type args struct {
ctx context.Context
name string
}
tests := []struct {
name string
args args
want string
wantErr bool
origin []interface{}
setupMocks []func()
verifyMocks func()
}{
{
name: "happy path",
args: args{
ctx: context.Background(),
name: "wdxxl",
},
want: "hello wdxxl",
wantErr: false,
origin: []interface{}{external.AuditLogClient},
setupMocks: []func() {
func () { // move out as a common Function
// mock interface
auditLogMock = &mocks.ILogClient{}
auditLogMock.On("AsyncSendAuditLog", mock.Anything, mock.Anything)
external.AuditLogClient = auditLogMock
},
},
verifyMocks: func() {
// verify the interface been called or not
auditLogMock.AssertNumberOfCalls(t, "AsyncSendAuditLog", 1)
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// golang unit test setup & restore individual
defer testtools.Restore(testtools.Pairs(tt.origin...)...)
for _, mocks := range tt.setupMocks() {
mocks()
}
defer tt.verifyMocks()

got, err := hello(tt.args.ctx, tt.args.name)
if (err != nil) != tt.wantErr {
t.Errorf("hello() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("hello() = %v, want %v", got, tt.want)
}
})
}
}