1. use mock data
假設需要測試一個介面,並不希望有data層面的互動(test方法中需要初始化db等配置)
首先需要改造UserServer, 讓 userData interface 注入,然後我可以實現userDataImpl (有*gorm.db注入),也可以實現mockDataimpl(內建map,記憶體儲存資料)
type UserServer struct { proto.UnimplementedUserServer db UserData } // data interface type UserData interface {
// handler中和databse互動的方法 GetUserByMobile(ctx context.Context, mobile string) (User, error) // 這個方法查詢出來後用來注入空User中,所以返回User Create(user User) (tx *gorm.DB) } // mock the data tier for test type userDataMock struct { userinfo map[string]User } func (u *userDataMock) GetUserByMobile(ctx context.Context, mobile string) (User, error) { return u.userinfo[mobile], nil } func (u *userDataMock) Create(user User) (tx *gorm.DB) { u.userinfo[user.Mobile] = user return nil } // impl the data tier, need db type userDataImpl struct { db *gorm.DB } func (u *userDataImpl) GetUserByMobile(ctx context.Context, mobile string) (User, error) { return User{}, nil } func (u *userDataImpl) Create(user *User) (tx *gorm.DB) { return u.db.Create(&user) } // init the impl func NewUserDataMock() *userDataMock { return &userDataMock{userinfo: make(map[string]User)} } func NewUserData(db *gorm.DB) *userDataImpl { return &userDataImpl{db: db} }
handler方法:
func (s *UserServer) CreateUser(ctx context.Context, req *proto.CreateUserInfo) (*proto.UserInfoRsp, error) { var user User user, _ = s.db.GetUserByMobile(ctx, req.Mobile) // UserServer的userData interface,適配mock資料需求和正常db連線需求 //result := s.db.Where(&User{Mobile: req.Mobile}).First(&user) //if result.RowsAffected == 1 { // return nil, status.Errorf(codes.AlreadyExists, "user already exists") //} user.Mobile = req.Mobile user.NickName = req.NickName options := &password.Options{16, 100, 30, sha512.New} salt, encodedPwd := password.Encode("generic password", options) user.Password = fmt.Sprintf("$sha512$%s$%s", salt, encodedPwd) //result = global.DB.Create(&user) //if result.Error != nil { // return nil, status.Errorf(codes.Internal, result.Error.Error()) //} _ = s.db.Create(user) // create user後database生成id -> 返回給呼叫方 rsp := ModelToRsp(user) return &rsp, nil }