如何使用相互依赖的接口方法模拟结构

How to mock structs with interdependent interface methods

我在为一个相当常见的 use-case/pattern.

用 Go 编写单元测试时遇到了问题

想象一下,如果你愿意,是这样的:

package main

type Resource struct {
    name string
}

type ResourceManager interface {
    GetResource(id string) (*Resource, error)
    GetAllResources() ([]*Resource, error)
}

type ResourceManagerImpl struct {
}

func (r *ResourceManagerImpl) GetResource(id string) (*Resource, error) {
    resource := &Resource{}
    var err error

    // fetch resource.
    // ...

    return resource,  err
}

func (r *ResourceManagerImpl) GetAllResources() ([]*Resource, error) {
    var resources []*Resource
    var err error

    // for _, id := range ids {
    //  resource = r.GetResource(id)
    //  resources = append(resources, resource)
    // }

    return resources, err
}

GetAllResources 根据需要重复调​​用 GetResource 是一种常见的模式。

我可以使用 gomocktestify 来测试 GetResource 的所有排列。但是,在测试 GetAllResource 时,我想模拟 GetResource。否则,测试将变成一场噩梦。如果 Java 使用部分模拟,这就是 easymockmockito 中的做法。但是,尚不清楚如何在 Golang 中实现相同的目标。

具体来说,我找不到如何部分模拟 struct。大多数建议都围绕打破这样的 struct 展开,但在这种情况下,struct 已经处于最低限度。为了测试而不破坏 ResourceManager 接口(分为单个和多个)似乎是一个公平的要求,因为这没有多大意义,充其量是笨拙的,并且不会像更多这样的方法那样很好地扩展进入界面

遇到这种情况我是这样处理的:

func (r *ResourceManagerImpl) GetAllResources() ([]*Resource, error) {
   return getAllResources(r)
}


func getAllResources(r ResourceManager) ([]*Resource,error) {
  ...
}

然后用模拟的 r 测试 getAllResources 而不是 GetAllResources。如果你遇到从代码中调用 GetAllResources 的情况,你必须模拟 GetAllResources,你可以这样做:

var getAllResources=func(r ResourceManager) ([]*Resource,error) {
...
}

并将 getAllResources 分配给测试实例。