关于使用 "gomock" 进行单元测试时,遇到一个 关于接口方法的意外调用问题。[不知道时规范问题还是我的使用方式有问题]

1. 运行环境

版本:go1.19.5 系统 Windows

2. 问题描述?

关于使用 “gomock” 进行单元测试时,遇到一个 关于接口方法的意外调用问题。【不知道是规范问题还是我的使用方式有问题,个人感觉应该是使用方法错了】

Service层接口

Repository层接口
如图,我使用gomock对,UserRepo接口的Create方法进行测试,但是运行测试用例的时候出现了text Unexpected call to *repository.Mo ckUserRepo.GetByNickName,这个错误测试用例不通过(问题是我需要在Register方法中调用GetByUseerName,因为需要对账户是否存在进行校验。所以是我的这种接口方法定义存在问题吗?很不解。)

    hashPwd := utils.MD5V("yyz", "salt", 10)
    testCases := []struct {
        name      string
        mock      func(ctrl *gomock.Controller) repository.UserRepo
        inputUser domain.User

        wantUser domain.User
        wantErr  error
    }{
        {
            name: "注册成功案例",
            mock: func(ctrl *gomock.Controller) repository.UserRepo {
                repo := repository.NewMockUserRepo(ctrl)
                //repo.EXPECT().GetByNickName(gomock.Any(), "xxn").Return(model.User{}, gorm.ErrRecordNotFound)
                //repo.EXPECT().GetByUserName(gomock.Any(), "小仙女郁郁症").Return(model.User{}, gorm.ErrRecordNotFound)
                repo.EXPECT().Create(gomock.Any(), domain.User{
                    UserName: "xxn", Password: "yyz", NickName: "小仙女郁郁症",
                }).Return(uint64(1), nil)
                return repo
            },
            inputUser: domain.User{UserName: "xxn", Password: "yyz", NickName: "小仙女郁郁症"},
            wantUser:  domain.User{ID: 1, UserName: "xxn", Password: hashPwd, NickName: "小仙女郁郁症"},
        },
    }

    for _, tc := range testCases {
        t.Run(tc.name, func(t *testing.T) {
            ctrl := gomock.NewController(t)
            defer ctrl.Finish()
            // 通过Mock 获得Repo构造对象
            repo := tc.mock(ctrl)
            // 下面创建Service进行测试
            svc := NewUserService(repo)
            // 下边进行 Service层接口调试
            user, err := svc.Register(context.Background(), tc.inputUser)
            // 成功案例
            assert.Equal(t, tc.wantErr, err)
            if err != nil {
                return
            }
            // 失败案例
            assert.Equal(t, tc.wantUser, user)
        })

3. 您期望得到的结果?

// 这行代码内部调用了  GetByNickName 和 GetByUserName 方法。
user, err := svc.Register(context.Background(), tc.inputUser)
// 似乎我想要把这个测试用例跑通必须要覆盖上面的两个方法。但是我尝试过没用。

4. 您实际得到的结果?

=== RUN   TestUserService
--- FAIL: TestUserService (555.70s)
=== RUN   TestUserService/注册成功案例
    user.go:102: Unexpected call to *repository.Mo      ckUserRepo.GetByNickName([context.Background 小仙女郁郁症]) at H:/code/go/privat      e/demo/xmlt/internal/repository/mock_user.repo.go:72 because: there are no expected calls of the method "GetByNickName" for that receiver
    panic.go:540: missing call(s) to *repository.M      ockUserRepo.Create(is anything, is equal to {0 xxn yyz 小仙女郁郁症     0001-01-      01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC}) H:/code/go/private/demo/xmlt/internal/service/user_test.go:29
    panic.go:540: aborting test due to missing cal      l(s)
最佳答案
package service

import (
    "context"
    "github.com/golang/mock/gomock"
    "github.com/stretchr/testify/assert"
    "gorm.io/gorm"
    "testing"
    "xmlt/internal/domain"
    "xmlt/internal/model"
    "xmlt/internal/repository"
    "xmlt/utils"
)

func TestUserService(t *testing.T) {
    hashPwd := utils.MD5V("yyz", "salt", 10)
    testCases := []struct {
        name      string
        mock      func(ctrl *gomock.Controller) repository.UserRepo
        inputUser domain.User

        wantUser domain.User
        wantErr  error
    }{
        {
            name:      "注册成功案例",
            inputUser: domain.User{UserName: "xxn", Password: "yyz", NickName: "小仙女郁郁症"},
            mock: func(ctrl *gomock.Controller) repository.UserRepo {
                repo := repository.NewMockUserRepo(ctrl)
                repo.EXPECT().GetByUserName(gomock.Any(), "xxn").Return(model.User{}, gorm.ErrRecordNotFound)
                repo.EXPECT().GetByNickName(gomock.Any(), "小仙女郁郁症").Return(model.User{}, gorm.ErrRecordNotFound)
                repo.EXPECT().Create(gomock.Any(), domain.User{UserName: "xxn", Password: hashPwd, NickName: "小仙女郁郁症"}).Return(uint64(1), nil)
                return repo
            },

            wantUser: domain.User{ID: 1, UserName: "xxn", Password: hashPwd, NickName: "小仙女郁郁症"},
        },
    }

    for _, tc := range testCases {
        t.Run(tc.name, func(t *testing.T) {
            ctrl := gomock.NewController(t)
            defer ctrl.Finish()
            // 通过Mock 获得Repo构造对象
            repo := tc.mock(ctrl)
            // 下面创建Service进行测试
            svc := NewUserService(repo)
            // 下边进行 Service层接口调试
            user, err := svc.Register(context.Background(), tc.inputUser)
            // 错误一致
            assert.Equal(t, tc.wantErr, err)
            if err != nil {
                return
            }
            // 数据一致
            assert.Equal(t, tc.wantUser, user)
        })
    }
}

已解决(多方面原因,上述代码可通过)

11个月前 评论
讨论数量: 2

搜索引擎查一下gomock函数打桩

11个月前 评论
package service

import (
    "context"
    "github.com/golang/mock/gomock"
    "github.com/stretchr/testify/assert"
    "gorm.io/gorm"
    "testing"
    "xmlt/internal/domain"
    "xmlt/internal/model"
    "xmlt/internal/repository"
    "xmlt/utils"
)

func TestUserService(t *testing.T) {
    hashPwd := utils.MD5V("yyz", "salt", 10)
    testCases := []struct {
        name      string
        mock      func(ctrl *gomock.Controller) repository.UserRepo
        inputUser domain.User

        wantUser domain.User
        wantErr  error
    }{
        {
            name:      "注册成功案例",
            inputUser: domain.User{UserName: "xxn", Password: "yyz", NickName: "小仙女郁郁症"},
            mock: func(ctrl *gomock.Controller) repository.UserRepo {
                repo := repository.NewMockUserRepo(ctrl)
                repo.EXPECT().GetByUserName(gomock.Any(), "xxn").Return(model.User{}, gorm.ErrRecordNotFound)
                repo.EXPECT().GetByNickName(gomock.Any(), "小仙女郁郁症").Return(model.User{}, gorm.ErrRecordNotFound)
                repo.EXPECT().Create(gomock.Any(), domain.User{UserName: "xxn", Password: hashPwd, NickName: "小仙女郁郁症"}).Return(uint64(1), nil)
                return repo
            },

            wantUser: domain.User{ID: 1, UserName: "xxn", Password: hashPwd, NickName: "小仙女郁郁症"},
        },
    }

    for _, tc := range testCases {
        t.Run(tc.name, func(t *testing.T) {
            ctrl := gomock.NewController(t)
            defer ctrl.Finish()
            // 通过Mock 获得Repo构造对象
            repo := tc.mock(ctrl)
            // 下面创建Service进行测试
            svc := NewUserService(repo)
            // 下边进行 Service层接口调试
            user, err := svc.Register(context.Background(), tc.inputUser)
            // 错误一致
            assert.Equal(t, tc.wantErr, err)
            if err != nil {
                return
            }
            // 数据一致
            assert.Equal(t, tc.wantUser, user)
        })
    }
}

已解决(多方面原因,上述代码可通过)

11个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!