go - 我是否应该始终将结构属性定义为可测试性的接口(interface)?

标签 go

据我所知,在 Go 中模拟结构依赖的唯一方法是使用接口(interface)。所以我的问题是:如果我的结构具有执行某些操作的方法(当结构不仅仅是存储数据的模型时),我是否应该始终将属性定义为接口(interface)以便正确地模拟和测试它?

简单的例子:

type UserService struct {
    userRepository UserRepository
}

func (us *UserService) MaleUsers() []User {
    all := us.userRepository.FindAll()
    maleUsers := []User{}
    for _, u := range all {
        if u.gender == "male" {
            maleUsers = append(maleUsers, u)
        }
    }
    return maleUsers
}

假设我们有一个用户服务,它有一个依赖项:repository。 服务具有获取所有用户然后按某些条件过滤它们的方法。 顺便说一句,过滤逻辑可以放在一个单独的依赖项中,以避免在服务方法 (SRP) 中进行过滤。

顺便说一句。我来自 Java 世界。如果这种构建应用程序的方法在 Go 中不符合概念,请告诉我。

最佳答案

为了模拟 UserServiceuserRepository 依赖项,您认为最好的方法是使用接口(interface)是正确的。

首先,创建您的界面:

type UserRepository interface {
    FindAll() []Users
}

然后构建一个模拟:

type MockUserRepository struct{}

func (mock MockUserRepository) FindAll() []Users {
    // here you would manually build a slice of users and return it
    return []Users
}

最后,在你的测试用例中使用这个 mock 作为依赖:

func TestMaleUsers(t *testing.T) {
    // compose service using mock
    service := UserService {
        userRepository: MockUserRepository,
    }

    // get output of method call
    users := service.MaleUsers()

    // perform assertions on output
}

通过这种方式,您已经创建了一个模拟接口(interface),可以在您的测试中使用它,而无需对您的存储库执行任何数据库调用。

关于go - 我是否应该始终将结构属性定义为可测试性的接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45262846/

相关文章:

go - UTC()调用是否在rand.Seed(time.Now()。UTC()。UnixNano())中冗余?

Golang 如何保证数据在一个 goroutine 中完成,同时被另一个 goroutine 访问

go - 在Go中使用引用处理 slice 时是否存在错误?

Cgo:如何将双数组从 C 返回到 Go

go - 无法导入 gorilla/mux(github.com/gorilla/mux@v1.7.4 : is explicitly required in go. mod,但在 vendor/modules.txt 中未标记为显式)

Golang接口(interface)的正确使用

unicode - 连接 net.Addr 和 []rune

Golang md5 Write vs Sum - 为什么输出不同?

go - 将文本文件读入字符串数组(并写入)

recursion - 从路径字符串中获取树状结构