

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# AWS SDK for Go v2를 사용한 유닛 테스트
<a name="unit-testing"></a>

 애플리케이션에서 SDK를 사용하는 경우 애플리케이션의 유닛 테스트를 위해 SDK의 모의 테스트를 진행해야 할 수 있습니다. SDK를 모의 테스트하면 SDK 내부가 아닌 테스트 대상에 중점을 두고 테스트를 진행할 수 있습니다.

 모의 테스트를 지원하려면 `s3.Client`와 같은 구체적인 서비스 클라이언트, 페이지네이터 및 웨이터 유형 대신 Go 인터페이스를 사용합니다. 이를 통해 애플리케이션은 종속성 주입과 같은 패턴을 사용하여 애플리케이션 로직을 테스트할 수 있습니다.

## 클라이언트 작업 모의 테스트
<a name="mocking-client-operations"></a>

 이 예제에서 `S3GetObjectAPI`는 `GetObjectFromS3` 함수에 필요한 Amazon S3 API 작업 세트를 정의하는 인터페이스입니다. `S3GetObjectAPI`는 Amazon S3 클라이언트의 [GetObject](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#Client.GetObject) 메서드에 의해 충족됩니다.

```
import "context"
import "github.com/aws/aws-sdk-go-v2/service/s3"

// ...

type S3GetObjectAPI interface {
    GetObject(ctx context.Context, params *s3.GetObjectInput, optFns ...func(*s3.Options)) (*s3.GetObjectOutput, error)
}

func GetObjectFromS3(ctx context.Context, api S3GetObjectAPI, bucket, key string) ([]byte, error) {
    object, err := api.GetObject(ctx, &s3.GetObjectInput{
        Bucket: &bucket,
        Key:    &key,
    })
    if err != nil {
        return nil, err
    }
    defer object.Body.Close()

    return ioutil.ReadAll(object.Body)
}
```

 `GetObjectFromS3` 함수를 테스트하려면 `mockGetObjectAPI`를 사용하여 `S3GetObjectAPI` 인터페이스 정의를 충족합니다. 그런 다음 `mockGetObjectAPI` 유형을 사용하여 서비스 클라이언트에서 반환된 출력 및 오류 응답을 모의 테스트합니다.

```
import "testing"
import "github.com/aws/aws-sdk-go-v2/service/s3"

// ...

type mockGetObjectAPI func(ctx context.Context, params *s3.GetObjectInput, optFns ...func(*s3.Options)) (*s3.GetObjectOutput, error)

func (m mockGetObjectAPI) GetObject(ctx context.Context, params *s3.GetObjectInput, optFns ...func(*s3.Options)) (*s3.GetObjectOutput, error) {
    return m(ctx, params, optFns...)
}

func TestGetObjectFromS3(t *testing.T) {
    cases := []struct {
        client func(t *testing.T) S3GetObjectAPI
        bucket string
        key string
        expect []byte
    }{
        {
            client: func(t *testing.T) S3GetObjectAPI {
                return mockGetObjectAPI(func(ctx context.Context, params *s3.GetObjectInput, optFns ...func(*s3.Options)) (*s3.GetObjectOutput, error) {
                    t.Helper()
                    if params.Bucket == nil {
                        t.Fatal("expect bucket to not be nil")
                    }
                    if e, a := "fooBucket", *params.Bucket; e != a {
                        t.Errorf("expect %v, got %v", e, a)
                    }
                    if params.Key == nil {
                        t.Fatal("expect key to not be nil")
                    }
                    if e, a := "barKey", *params.Key; e != a {
                        t.Errorf("expect %v, got %v", e, a)
                    }

                    return &s3.GetObjectOutput{
                        Body: ioutil.NopCloser(bytes.NewReader([]byte("this is the body foo bar baz"))),
                    }, nil
                })
            },
            bucket: "amzn-s3-demo-bucket>",
            key:    "barKey",
            expect: []byte("this is the body foo bar baz"),
        },
    }

    for i, tt := range cases {
        t.Run(strconv.Itoa(i), func(t *testing.T) {
            ctx := context.TODO()
            content, err := GetObjectFromS3(ctx, tt.client(t), tt.bucket, tt.key)
            if err != nil {
                t.Fatalf("expect no error, got %v", err)
            }
            if e, a := tt.expect, content; bytes.Compare(e, a) != 0 {
                t.Errorf("expect %v, got %v", e, a)
            }
        })
    }
}
```

## 모의 테스트 페이지네이터
<a name="mocking-paginators"></a>

 서비스 클라이언트와 마찬가지로 페이지네이터에 대한 Go 인터페이스를 정의하여 페이지네이터를 모의 테스트할 수 있습니다. 해당 인터페이스는 애플리케이션의 코드에서 사용됩니다. 이를 통해 애플리케이션을 실행할 때 SDK의 구현을 사용하고 테스트에 구현을 모의 테스트할 수 있습니다.

 다음 예제에서 `ListObjectsV2Pager`는 `CountObjects` 함수에 필요한 Amazon S3 [ListObjectsV2Paginator](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#ListObjectsV2Paginator)의 동작을 정의하는 인터페이스입니다.

```
import "context"
import "github.com/aws/aws-sdk-go-v2/service/s3"

// ...

type ListObjectsV2Pager interface {
    HasMorePages() bool
    NextPage(context.Context, ...func(*s3.Options)) (*s3.ListObjectsV2Output, error)
}

func CountObjects(ctx context.Context, pager ListObjectsV2Pager) (count int, err error) {
    for pager.HasMorePages() {
        var output *s3.ListObjectsV2Output
        output, err = pager.NextPage(ctx)
        if err != nil {
            return count, err
        }
        count += int(output.KeyCount)
    }
    return count, nil
}
```

 `CountObjects`를 테스트하려면 `ListObjectsV2Pager` 인터페이스 정의를 충족하는 `mockListObjectsV2Pager` 유형을 생성합니다. 그런 다음 `mockListObjectsV2Pager`를 사용하여 서비스 작업 페이지네이터의 출력 및 오류 응답의 페이징 동작을 복제합니다.

```
import "context"
import  "fmt"
import "testing"
import "github.com/aws/aws-sdk-go-v2/service/s3"

// ...

type mockListObjectsV2Pager struct {
    PageNum int
    Pages   []*s3.ListObjectsV2Output
}

func (m *mockListObjectsV2Pager) HasMorePages() bool {
    return m.PageNum < len(m.Pages)
}

func (m *mockListObjectsV2Pager) NextPage(ctx context.Context, f ...func(*s3.Options)) (output *s3.ListObjectsV2Output, err error) {
    if m.PageNum >= len(m.Pages) {
        return nil, fmt.Errorf("no more pages")
    }
    output = m.Pages[m.PageNum]
    m.PageNum++
    return output, nil
}

func TestCountObjects(t *testing.T) {
    pager := &mockListObjectsV2Pager{
        Pages: []*s3.ListObjectsV2Output{
            {
                KeyCount: 5,
            },
            {
                KeyCount: 10,
            },
            {
                KeyCount: 15,
            },
        },
    }
    objects, err := CountObjects(context.TODO(), pager)
    if err != nil {
        t.Fatalf("expect no error, got %v", err)
    }
    if expect, actual := 30, objects; expect != actual {
        t.Errorf("expect %v, got %v", expect, actual)
    }
}
```