【问题标题】:How to mock structs with interdependent interface methods如何使用相互依赖的接口方法模拟结构
【发布时间】:2023-03-05 02:46:01
【问题描述】:

我在 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。大多数建议都围绕着打破structs,但在这种情况下,struct 已经处于最低限度。为了测试,不要破坏ResourceManager 接口(分为单接口和多接口)似乎是一个公平的要求,因为这没有多大意义,而且充其量是笨拙的,并且随着更多这样的方法进入,也不能很好地扩展界面。

【问题讨论】:

    标签: unit-testing go testing mocking go-interface


    【解决方案1】:

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

    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 分配给一个测试实例。

    【讨论】:

    • 看起来这是我们能做的最好的了。生成的代码仍然有多余的部分,但它可以工作。现在就可以了。
    猜你喜欢
    • 1970-01-01
    • 2021-08-25
    • 1970-01-01
    • 1970-01-01
    • 2019-05-29
    • 2014-06-24
    • 1970-01-01
    • 2019-02-19
    • 2011-01-25
    相关资源
    最近更新 更多