В настоящее время я пытаюсь привыкнуть к TDD, и в текущем проекте, над которым я работаю, я пытаюсь использовать Go SDK AWS. Это все прекрасно и денди, и я использовал его раньше, но сейчас я пытаюсь издеваться над значением, которое отправляет *ec2.DescribeVolumesOutput
.
Погружаясь в код, я вижу, что возвращается для *ec2.DescribeVolumesOutput
:
type DescribeVolumesOutput struct {
_ struct{} `type:"structure"`
// The NextToken value to include in a future DescribeVolumes request. When
// the results of a DescribeVolumes request exceed MaxResults, this value can
// be used to retrieve the next page of results. This value is null when there
// are no more results to return.
NextToken *string `locationName:"nextToken" type:"string"`
// Information about the volumes.
Volumes []*Volume `locationName:"volumeSet" locationNameList:"item" type:"list"`
}
Хорошо.. Это круто, но то, что я хочу имитировать, должно жить внутри Volumes []*Volume
locationName:"volumeSet" locationNameList:"item" type:"list"`, так что давайте немного углубимся и посмотрим, что это такое...
type Volume struct {
_ struct{} `type:"structure"`
// Information about the volume attachments.
Attachments []*VolumeAttachment `locationName:"attachmentSet" locationNameList:"item" type:"list"`
// The Availability Zone for the volume.
AvailabilityZone *string `locationName:"availabilityZone" type:"string"`
// The time stamp when volume creation was initiated.
CreateTime *time.Time `locationName:"createTime" type:"timestamp"`
// Indicates whether the volume will be encrypted.
Encrypted *bool `locationName:"encrypted" type:"boolean"`
// The number of I/O operations per second (IOPS) that the volume supports.
// For Provisioned IOPS SSD volumes, this represents the number of IOPS that
// are provisioned for the volume. For General Purpose SSD volumes, this represents
// the baseline performance of the volume and the rate at which the volume accumulates
// I/O credits for bursting. For more information, see Amazon EBS Volume Types
// (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSVolumeTypes.html)
// in the Amazon Elastic Compute Cloud User Guide.
//
// Constraints: Range is 100-16,000 IOPS for gp2 volumes and 100 to 64,000IOPS
// for io1 volumes, in most Regions. The maximum IOPS for io1 of 64,000 is guaranteed
// only on Nitro-based instances (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html#ec2-nitro-instances).
// Other instance families guarantee performance up to 32,000 IOPS.
//
// Condition: This parameter is required for requests to create io1 volumes;
// it is not used in requests to create gp2, st1, sc1, or standard volumes.
Iops *int64 `locationName:"iops" type:"integer"`
// The full ARN of the AWS Key Management Service (AWS KMS) customer master
// key (CMK) that was used to protect the volume encryption key for the volume.
KmsKeyId *string `locationName:"kmsKeyId" type:"string"`
// The size of the volume, in GiBs.
Size *int64 `locationName:"size" type:"integer"`
// The snapshot from which the volume was created, if applicable.
SnapshotId *string `locationName:"snapshotId" type:"string"`
// The volume state.
State *string `locationName:"status" type:"string" enum:"VolumeState"`
// Any tags assigned to the volume.
Tags []*Tag `locationName:"tagSet" locationNameList:"item" type:"list"`
// The ID of the volume.
VolumeId *string `locationName:"volumeId" type:"string"`
// The volume type. This can be gp2 for General Purpose SSD, io1 for Provisioned
// IOPS SSD, st1 for Throughput Optimized HDD, sc1 for Cold HDD, or standard
// for Magnetic volumes.
VolumeType *string `locationName:"volumeType" type:"string" enum:"VolumeType"`
}
Хороший! это похоже на некоторые данные, над которыми я хочу издеваться!
Но за последние пару дней мне не удалось на самом деле издеваться над этими значениями. Они настолько вложены, что этот тип насмешек не стоит усилий? Даже попытка использовать github.com/aws/aws-sdk-go/service/ec2/ec2iface
, похоже, не помогает мне понять, как правильно упаковать некоторые фиктивные значения, возвращаемые для тестирования. Я ошибаюсь в TDD? я пропустил что-то супер очевидное? У меня действительно нет примера кода для демонстрации, так как я больше не понимаю, что я пытаюсь сделать.
У кого-нибудь есть пример того, как они издевались над этим?
@diyoda_ Мне еще предстоит создать методы, так как я пытаюсь использовать TDD, но терплю неудачу и сначала пытаюсь создать тесты. В основном метод будет использовать DescribeVolumesOutput
для проверки каждого тома на наличие тегов и возврата VolumeId для каждого. поэтому я хочу издеваться над значениями тегов и идентификаторами томов.
Невозможно издеваться над типом, вы можете издеваться только над реализацией интерфейса. В вашем случае я предполагаю, что вы пытаетесь вызвать DescribeVolumes и в ответ получаете построенное вами значение. Для этого вам нужно создать макет, например
type MockEC2API struct {
ec2iface.EC2API // embedding of the interface is needed to skip implementation of all methods
DescribeVolumesMethod func(*ec2.DescribeVolumesInput) (*ec2.DescribeVolumesOutput, error)
}
func (m *MockEC2API) DescribeVolumes(in *ec2.DescribeVolumesInput) (*ec2.DescribeVolumesOutput, error) {
if m.DescribeVolumesMethod != nil {
return m.DescribeVolumesMethod(in)
}
return nil, nil // return any value you think is good for you
}
В тесте создайте экземпляр MockEC2API
вместо настоящего ec2.EC2
и снабдите его функцией, которая будет вызываться и возвращать подготовленный вами ec2.DescribeVolumesOutput
результат.
...
ec2 := &MockEC2API{
DescribeVolumesMethod: func(*ec2.DescribeVolumesInput) (*ec2.DescribeVolumesOutput, error) {
return &ec2.DescribeVolumesOutput{...your initialization...}, nil
}
}
...
output, err := ec2.DescribeVolumes(in) // this output will be your prepared initialization
Потрясающий! Спасибо, это многое проясняет! Однако я все еще запутался в этой части &ec2.DescribeVolumesOutput{...your initialization...}
, если я не могу издеваться над типами, то как я должен сделать то, что есть на выходе? Думаю, я в основном потерялся в том, как подготовить ec2.DescribeVolumesOutput
результат.
Например, я хочу издеваться над значениями тега и идентификатора тома. Как мне их инициализировать?
@AlexCosta volumeId := "Your mock for VolumeId"
tagKey := "Your mock for Tag Key"
tagValue := "Your mock for Tag Value"
tag := ec2.Tag{Key: &tagKey, Value: &tagValue}
mocked := &ec2.DescribeVolumesOutput{
Volumes: []*ec2.Volume{{VolumeId: &volumeId, Tags: []*ec2.Tag{&tag}}}
}
ААААААА Спасибо! Теперь это имеет для меня смысл!
Прошло 2 года, а он по-прежнему полезен. Действительно хороший пример, примите мой голос!
можете ли вы рассказать о методах, которые вы вызываете, чтобы получить это
DescribeVolumesOutput
Хитрость должна заключаться в том, чтобы смоделировать метод службы и ожидать уже известное значение.