如何在golang中测试Map对象

hzbexzde  于 2022-12-07  发布在  Go
关注(0)|答案(1)|浏览(170)

我试着在我的go代码中实现一些单元测试,发现模拟方法的主题相当困难。我有下面的例子,希望你能帮助我:)
在第一层我有下面的代码:

package api

import (
    "fmt"
    "core"
)

type createUserDTO struct {
    Id string
}

func ApiMethod() {
    fmt.Println("some incoming api call wit user")
    incomingUserData := &createUserDTO{Id: "testId"}
    mapedUser := incomingUserData.mapUser()
    mapedUser.Create()
}

func (createUserDTO *createUserDTO) mapUser() core.User {
    return &core.UserCore{Id: createUserDTO.Id}
}

第二层有以下代码:

package core

import (
    "fmt"
)

type CoreUser struct{ Id string }

type User interface {
    Create()
}

func (user CoreUser) Create() {
    fmt.Println("Do Stuff")
}

我现在的问题是,我如何在不测试核心包的情况下测试api包中的每一个公共方法,尤其是方法Create()。

0x6upsns

0x6upsns1#

基于这些评论,我创建了一个简单的GitHub仓库来展示我通常是如何在Go语言中处理结构化项目的。目前仓库还没有考虑测试部分,但是用这个项目结构插入测试部分应该是很容易的。
让我们从常规文件夹的布局开始:

  • controllers
  • services
  • db
  • dto
  • models

现在,我们来看看相关的文件。

models/user.go
package models

import "gorm.io/gorm"

type User struct {
    *gorm.Model
    Id string `gorm:"primaryKey"`
}

func NewUser(id string) *User {
    return &User{Id: id}
}

此处为简单结构定义。

dto/user.go
package dto

import "time"

type UserDTO struct {
    Id      string    `json:"id"`
    AddedOn time.Time `json:"added_on"`
}

func NewUserDTO(id string) *UserDTO {
    return &UserDTO{Id: id}
}

我们使用一个虚拟的AddedOn字段来丰富模型结构,该字段仅用于演示。

db/user.go
package db

import (
    "gorm.io/gorm"

    "userapp/models"
)

type UserDb struct {
    Conn *gorm.DB
}

type UserDbInterface interface {
    SaveUser(user *models.User) error
}

func (u *UserDb) SaveUser(user *models.User) error {
    if dbTrn := u.Conn.Create(user); dbTrn.Error != nil {
        return dbTrn.Error
    }
    return nil
}

这里,我们定义了一个使用User仓库的接口,在我们的测试中,我们可以提供一个mock来代替UserDb结构体的示例。

services/user.go
package services

import (
    "time"

    "userapp/db"
    "userapp/dto"
    "userapp/models"
)

type UserService struct {
    DB db.UserDbInterface
}

type UserServiceInterface interface {
    AddUser(inputReq *dto.UserDTO) (*dto.UserDTO, error)
}

func NewUserService(db db.UserDbInterface) *UserService {
    return &UserService{
        DB: db,
    }
}

func (u *UserService) AddUser(inputReq *dto.UserDTO) (*dto.UserDTO, error) {
    // here you can write complex logic
    user := models.NewUser(inputReq.Id)

    // invoke db repo
    if err := u.DB.SaveUser(user); err != nil {
        return nil, err
    }

    inputReq.AddedOn = time.Now()

    return inputReq, nil
}

这是在表示层和底层存储库之间建立连接的层。

controllers/user.go
package controllers

import (
    "encoding/json"
    "io"
    "net/http"

    "userapp/dto"
    "userapp/services"
)

type UserController struct {
    US services.UserServiceInterface
}

func NewUserController(userService services.UserServiceInterface) *UserController {
    return &UserController{
        US: userService,
    }
}

func (u *UserController) Save(w http.ResponseWriter, r *http.Request) {
    reqBody, err := io.ReadAll(r.Body)
    if err != nil {
        panic(err)
    }
    r.Body.Close()

    var userReq dto.UserDTO

    json.Unmarshal(reqBody, &userReq)

    userRes, err := u.US.AddUser(&userReq)
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        json.NewEncoder(w).Encode(err)
        return
    }

    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(userRes)
}

这里,我们定义了(通过依赖注入)使用UserService结构的控制器。
你可以在GitHub上的我的存储库中找到所有的东西,如果它澄清了一点,请告诉我。

相关问题