【问题标题】:Mock external dependencies in golang在 golang 中模拟外部依赖项
【发布时间】:2019-01-18 19:32:30
【问题描述】:

我有一个连接到 AWS S3 并获取文件的程序。 我想为它写一些测试,但我想更一般地知道如何在 Golang 中进行这些模拟。我知道有一些库可以创建模拟,但如果我没记错的话,我读到有人建议只使用标准库进行单元测试是最好的方法。

那么,你将如何测试这样的函数?

func (s S3Input) Sample(key string) ([]byte, error) {
    var buf []byte
    waBuf := aws.NewWriteAtBuffer(buf)

    _, err := s.Downloader.Download(
        waBuf,
        &s3.GetObjectInput{
            Bucket: aws.String(s.Bucket),
            Key:    aws.String(key),
        },
    )
    if err != nil {
        return nil, err
    }

    return buf, nil
}

谢谢!

【问题讨论】:

  • 如果我查看您的代码,我不知道您想在那里测试什么逻辑。 Go 中的一般解决方案是将接口作为输入。然后,您将代码中的依赖项和测试中的模拟传递给该函数。
  • 这个函数没有提供任何“测试”,所以为什么要麻烦。
  • 你说得对,这段代码不需要太多测试。我的问题可能是一个更通用的问题,例如:“使用 Go 进行单元测试时的最佳实践是什么?”在 ruby​​ 中你可以使用双打,go 需要类似的东西还是有更直接的方法?

标签: unit-testing go


【解决方案1】:

一种方法是在结构中注入依赖项,如下所示:

type S3Inputer interface {
    NewWriteAtBuffer(buf []byte) *aws.WriteAtBuffer
    String(v string) *string
}

type S3Input struct {
    newWriteAtBufferFunc func(buf []byte) *aws.WriteAtBuffer
    stringFunc           func(v string) *string
}

func (s *S3Input) NewWriteAtBuffer(buf []byte) *WriteAtBuffer {
    return s.newWriteAtBufferFunc(buf)
}

func (s *S3Input) String(v string) *string {
    return s.stringFunc(v)
}

func (s S3Input) Sample(key string) ([]byte, error) {
    var buf []byte
    waBuf := s.NewWriteAtBuffer(buf)

    _, err := s.Downloader.Download(
        waBuf,
        &s3.GetObjectInput{
            Bucket: s.String(s.Bucket),
            Key:    s.String(key),
        },
    )
    if err != nil {
        return nil, err
    }

    return buf, nil
}

func main() {
    s := &S3Input{
        StringFunc:           aws.String,
        NewWriteAtBufferFunc: aws.NewWriteAtBuffer,
    }

    // ...
}

这允许您用您想要测试的任何内容替换这些功能,而无需任何测试框架。

然后,测试函数看起来像这样:

func (s S3Input) TestSample(t *testing.T) {
    s3Mock := &S3Input{
        StringFunc:           (func (v string) *string {
            return nil
        }),
        NewWriteAtBufferFunc: (func (buf []byte) *aws.WriteAtBuffer {
            return nil
        }),
    }

    res, err := s3Mock.Sample(...) //
    // asserts & error checks
}

您可以通过创建S3InputMock 类型而不是重用基础类型来改进它,两者都将实现S3Inputer 接口,并且您的模拟可以具有允许它帮助您进行测试的属性。例如,它可以计算函数被调用的次数、存储它接收到的参数、根据您设置的属性使其方法行为不同以便于测试等。

【讨论】:

  • 谢谢,这可能是测试它的一种方法,尽管正如其他人所说,这个特定的 sn-p 并不需要任何真正的测试,因为几乎没有逻辑。
  • 是的,但是这种方法并不特定于您的代码,它是一种能够测试依赖于外部依赖项的东西的通用方法 :) 如果我能提供更多帮助,请告诉我!
猜你喜欢
  • 1970-01-01
  • 2018-01-21
  • 1970-01-01
  • 2020-04-14
  • 1970-01-01
  • 2021-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多