在 golang 中模拟外部依赖

Syn*_*ync 6 unit-testing go

我有一个连接到 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
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

Ull*_*kut 6

一种方法是在您的结构中注入依赖项,例如:

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,
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

这允许您将这些功能替换为您想要进行测试的任何功能,而无需任何测试框架。

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

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
}
Run Code Online (Sandbox Code Playgroud)

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