mar*_*ins 6 unit-testing dependency-injection amazon-s3 go amazon-web-services
我有一个接受路径和 S3Client 的函数:
ListObjects(folder, s3Client)
我希望它接受生产中的“真实”客户端。即:s3.New(session.New()
但是当我运行测试时,我希望它接受我的模拟版本,这样我们就不会在测试中与 AWS 对话。我实现此目的的方法是创建一个与真实 S3Client 和我的模拟版本相匹配的界面。
这是最好的方法还是我错过了什么?
首先,我使用我计划模拟的函数定义了接口。
package core
import "github.com/aws/aws-sdk-go/service/s3"
type MyS3ClientInterface interface {
ListObjects(input *s3.ListObjectsInput) (*s3.ListObjectsOutput, error)
}
Run Code Online (Sandbox Code Playgroud)
GetObjectsFromS3 的实现如下:
// GetObjectsFromS3 returns a list of objects found in provided path on S3
func GetObjectsFromS3(path string, s3Client core.MyS3ClientInterface) ([]*core.Asset, error) {
// build input variable
result, err := s3Client.ListObjects(input)
// cut..
}
Run Code Online (Sandbox Code Playgroud)
这是我的 s3Client.ListObjects 模拟版本
package test_awstools
import (
"github.com/aws/aws-sdk-go/service/s3"
)
type MyS3Client struct{}
func (m MyS3Client) ListObjects(input *s3.ListObjectsInput) (*s3.ListObjectsOutput, error) {
output := &s3.ListObjectsOutput{}
return output, nil
}
func (m MyS3Client) GetObject(input *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
// output := &s3.GetObject()
return nil, nil
}
Run Code Online (Sandbox Code Playgroud)
内部/awstools/bucket_test.go
1 package awstools
2
3 import (
4 "fmt"
5 "testing"
6
7 "internal/test_awstools"
8 )
9
10 func TestListObjects(t *testing.T) {
11 folder := "docs"
// Use my mocked version of the S3 client.
12 s3Client := &test_awstools.MyS3Client{}
// And I pass that along to the ListObject function
13 objects, err := ListObjects(folder, s3Client)
14 if err != nil {
15 t.Error(err)
16 }
17 fmt.Println(objects)
18 }
Run Code Online (Sandbox Code Playgroud)
小智 1
我建议的一个小改进是允许您的模拟结构接受一个函数,这样它可以在测试之间有所不同。像这样的东西:
package test_awstools
import (
"github.com/aws/aws-sdk-go/service/s3"
)
type MyS3Client struct {
ListObjectsFunc func(*s3.ListObjectsInput) (*s3.ListObjectsOutput, error)
GetObjectFunc func(*s3.GetObjectInput) (*s3.GetObjectOutput, error)
}
func (m *MyS3Client) ListObjects(input *s3.ListObjectsInput) (*s3.ListObjectsOutput, error) {
return m.ListObjectsFunc(input)
}
func (m *MyS3Client) GetObject(input *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
return m.GetObjectFunc(input)
}
Run Code Online (Sandbox Code Playgroud)
现在,在您的测试中,您可以*Func在结构上设置值,以便您的测试对存根行为更具声明性:
func TestListObjects(t *testing.T) {
folder := "docs"
// Use my mocked version of the S3 client.
s3Client := &test_awstools.MyS3Client{}
// Set the ListObjectsFunc to behave the way you want
s3Client.ListObjectsFunc = func(input *s3.ListObjectsInput) (*s3.ListObjectsOutput, error) {
output := &s3.ListObjectsOutput{}
return output, nil
}
// Make the call to list objects (which is now mocked)
objects, err := s3Client.ListObjects(folder, s3Client)
// Do your assertions
if err != nil {
t.Error(err)
}
fmt.Println(objects)
}
Run Code Online (Sandbox Code Playgroud)