I'm rather new to Go and I can't seem to wrap my head around it's struct/interface system while trying to create a mock object for an AWS s3manager uploader's unit testing.
In my package file I have:
package uploader
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
"os"
)
func GetS3Uploader() *s3manager.Uploader {
conf := aws.Config{Region: aws.String("eu-west-1")}
sess := session.New(&conf)
uploader := s3manager.NewUploader(sess)
return uploader
}
func uploadFile(uploader interface{}) {
uploader.Upload(&s3manager.UploadInput{
Bucket: aws.String("A"),
Key: aws.String("B"),
Body: bytes.NewReader([]byte("C")),
})
}
and in the matching uploader_test.go there is the following code, containing the mock objects:
package uploader_test
import (
. "github.com/onsi/ginkgo"
. "github.com/something/reponame/uploader"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
)
type mockUploadOutput struct {
Location string
VersionID *string
UploadID string
}
type mockUploader struct {
}
func (*mockUploader) Upload(input *s3manager.UploadInput) (mockUploadOutput, error) {
versionID := "TESTVERSION"
mockUploadResponse := mockUploadOutput{
Location: "TESTLOCATION",
VersionID: &versionID,
UploadID: "TESTUPLOADID",
}
return mockUploadResponse, nil
}
var _ = Describe("Reportuploader", func() {
var (
mockUp mockUploader
)
Describe("Upload()", func() {
Context("With mocked uploader object", func() {
It("should return the predefined mockUploadResponse", func() {
uploadFile(mockUp)
})
})
})
})
But when I try to run it, I get the following error:
uploader.Upload undefined (type interface {} is interface with no methods)
My aim is to have the uploadFile function accept both the *s3manager.Uploader object and the mocked mockUploader as valid arguments, and recognize both their Upload methods. I tried asserting the type before calling the Upload method, but that only gave a different error. Can anyone help, and tell me what am I doing wrong?
You set the type signature to func uploadFile(uploader interface{}) {
, which means it accepts anything as an argument, but you cannot call any method on uploader
, because your type signature interface{}
does not any methods on it.
It looks like what you want to do is:
type Uploader interface {
Upload(input *s3manager.UploadInput)
}
func uploadFile(uploader Uploader) {
uploader.Upload(&s3manager.UploadInput{
Bucket: aws.String("A"),
Key: aws.String("B"),
Body: bytes.NewReader([]byte("C")),
})
}
But you are going to need to match the function signature, and it looks like one of them has:
(mockUploadOutput, error)
and the other a
(*s3manager.UploadOutput, error)
so, what I would probably do is just return a real (*s3manager.UploadOutput, error)
from your mock:
func (*mockUploader) Upload(input *s3manager.UploadInput) (*s3manager.UploadOutput, error) {
versionID := "TESTVERSION"
mockUploadResponse := &s3manager.UploadOutput{
Location: "TESTLOCATION",
VersionID: &versionID,
UploadID: "TESTUPLOADID",
}
return mockUploadResponse, nil
}