dongpai1942 2018-08-11 11:18
浏览 57
已采纳

在Golang中模拟外部依赖项

I have a program in go that connects to AWS S3 and gets a file. I'd like to write some tests for it, but I'd like to know, more generally, how to do these mocks in Golang. I know there are some libraries to create mocks but if I remember correctly I read someone suggesting using only standard libraries for unit tests was the best way to go.

So, how would you test a function like this?

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
}

Thank you!

  • 写回答

1条回答 默认 最新

  • doutuo2829 2018-08-11 11:40
    关注

    One way to do it is to inject the dependencies in your structure, like such:

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

    This allows you to replace those functions with whatever you want for testing, without the need of any testing framework.

    Then, the testing function would look something like this:

    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
    }
    

    You could improve it by creating a S3InputMock type instead of reusing the base one, both would implement the S3Inputer interface and your mock could have attributes allowing it to help you with testing. For example, it could count the number of times a function is called, store the arguments it received, have its methods behave differently depending on the attributes you set for easier testing, etc.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 对于这个复杂问题的解释说明
  • ¥50 三种调度算法报错 有实例
  • ¥15 关于#python#的问题,请各位专家解答!
  • ¥200 询问:python实现大地主题正反算的程序设计,有偿
  • ¥15 smptlib使用465端口发送邮件失败
  • ¥200 总是报错,能帮助用python实现程序实现高斯正反算吗?有偿
  • ¥15 对于squad数据集的基于bert模型的微调
  • ¥15 为什么我运行这个网络会出现以下报错?CRNN神经网络
  • ¥20 steam下载游戏占用内存
  • ¥15 CST保存项目时失败