1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Golangはじめて物語(第6話: DynamoDB local+testingでお手軽に回帰テストする)

Last updated at Posted at 2020-11-29

はじめに

Golangのテスト方法については、第一話でも少し触れたが、実際に動かす際には、DynamoDB等のAWSサービスの本物に接続するか、モックが必要になったりして、あの内容だけでは実用部分に欠けていた。

今回は、DynamoDB local をモックとしてローカル環境で動かし、実際にそこに接続するための実装を整理する。

ベースとなるソースコードは、上記の第一話のソースコードにする。

DynamoDB local を起動する

毎度手動で起動してから go test を実行するのは面倒なので、make test の中でサクっと起動できるようにしてしまいたい。
以下のように docker-compose の力を借りて起動をしよう。

docker-compose.yml
version: '3'
services:
  dynamodb-local:
    image: amazon/dynamodb-local
    ports:
      - "8000:8000"

main_test.go の変更点

dynamoDB に接続する箇所について以下のように変更する。

main_test.go
	svc := dynamodb.New(sess, &aws.Config{Endpoint: aws.String("http://localhost:8000")})

どうせテストコードはテスト環境でしか動かさないので、固定してしまえば良いだろう。必要があれば、環境変数やプロパティから渡すようにしておこう。

また、以前の記事ではデータ敷き込み時にテーブルが既に作られていることを前提に書いていたが、今回は DynamoDB local は毎回起動時に真っ新になるので、以下のように setup() 関数内でテーブルを作っておく。

main_test.go
	input := &dynamodb.CreateTableInput{
		AttributeDefinitions: []*dynamodb.AttributeDefinition{
			{
				AttributeName: aws.String("id"),
				AttributeType: aws.String("S"),
			},
		},
		KeySchema: []*dynamodb.KeySchemaElement{
			{
				AttributeName: aws.String("id"),
				KeyType:       aws.String("HASH"),
			},
		},
		ProvisionedThroughput: &dynamodb.ProvisionedThroughput{
			ReadCapacityUnits:  aws.Int64(1),
			WriteCapacityUnits: aws.Int64(1),
		},
		TableName: aws.String("[テーブル名]"),
	}

	_, err := svc.CreateTable(input)
	if err != nil {
		return fmt.Errorf("setup() error: %w", err)
	}

気になるなら、以下のように teardown() 関数でテーブル削除をしておこう。
毎回 DynamoDB local を停止させるなら不要な操作ではある。

main_test.go
	input := &dynamodb.DeleteTableInput{
		TableName: aws.String("[テーブル名]"),
	}

	_, err := svc.DeleteTable(input)
	if err != nil {
		return fmt.Errorf("teardown() error: %w", err)
	}

プロダクトコードの変更点

プロダクトコード側は、以下のようにして dynamoDB への接続を制御する。
起動時に環境変数が export MODE_UT=TRUE されているときだけ、ローカルに接続し、そうでない場合はデフォルトのプロファイルでアクセスする。

main_test.go
	svc := func(mode_ut string) *dynamodb.DynamoDB {
		if(mode_ut != "TRUE"){
			return dynamodb.New(sess)
		} else {
			return dynamodb.New(sess, &aws.Config{Endpoint: aws.String("http://localhost:8000")})
		}
	}(os.Getenv("MODE_UT"))

別に svc を切り出して普通に if で分岐しても良いのだけど、なんか var にあれこれ書くの格好悪くてな……。

Makefileの変更点

makefile では test のマクロを以下のようにする。

Makefile
test:
	docker-compose up -d; \
	export MODE_UT=TRUE; \
	go clean -testcache; \
	go test -v -coverprofile=./c.out ./...; \
	go tool cover -func=c.out; \
	docker-compose down; \
	rm ./c.out
.PHONY: test

test clean -testcache はお好みで入れても入れなくても。
まあ、test -v も好みで良い(入れないとOKのときは何もログが出なくなる)。
-coverprocile することで、カバレッジ用の情報をダンプし、go tool cover でその情報をもとに実行結果を出してくれる。

↓こんな感じだ。

ok      モジュール名     0.965s  coverage: 55.6% of statements
モジュール名/main.go:19: init            0.0%
モジュール名/main.go:22: main            0.0%
モジュール名/main.go:26: handler         57.7%
total:                  (statements)    55.6%

この方法は Docker があれば使えるので、ローカル環境でもできるだろうし、AWS の EC2 上で起動してローカル環境からアクセスするようにしても良いだろう。CodeBuild でもできるような気がするが、未検証。docker-compose をインストールするか、docker run で直接走らせるかの工夫は必要になるだろう。

CodeBuild でも CI してみよう

さて、ローカルでの回帰テストができるようになったら、CI に組み込みたくなるのが世の常というもの。
Buildspec で DynamoDB Local を Docker で起動するなら、特権モードをつけておく必要がある。
コンソールでは環境編集画面の以下のチェックボックスだ。

キャプチャ.png

Terraform で作っている場合は、

resource "aws_codebuild_project" "test" {
  (中略)
  environment {
    (中略)
    privileged_mode = "true"
  }
  (後略)
}

だ。

CodeBuild で docker-compose するには、install フェーズに以下を入れる。

  install:
    runtime-versions:
      golang: 1.x
      docker: 19

なぜか AWSの公式ドキュメントには記載がないが、githubのコンテナ定義(この例では ubuntu:4.0) の runtimes.yml には

  docker:
    versions:
      18:
        commands:
          - echo "Using Docker 19"
      19:
        commands:
          - echo "Using Docker 19"

の記述があるので使えるのである。2021/2/28 現在、ubuntu:5.0 の最新版イメージにはなぜか docker の定義がないため、将来的には使えなくなる可能性があることを留意しておく(AL2 の最新版イメージには入っている)。

CodeBuild 上でも make から docker-compose を起動することはできるので、ちゃんと makefile を書いておけば、Buildspec で頑張ることはほとんどないはずだ。

あとは、せっかく CodeBuild に乗せたのだから、レポートを組み込むこともできるので有効活用してみよう。この場合、まだ CodeBuild のレポート機能が Golang の標準的な出力に対応していないため、

	$(GOPATH)/bin/go-junit-report < ../report/testresult.log > ../report/report.xml; \

	$(GOPATH)/bin/gocover-cobertura < ../report/cover.out > ../report/coverage.xml; \

を、Buildspec なり makefile に入れておく必要がある(詳細はそれぞれググってもらえば情報はいろいろと集められる)。
Buildspec でコマンドを入れるのであれば、

  install:
    (中略)
    commands:
      - go get github.com/jstemmer/go-junit-report
      - go get github.com/t-yuki/gocover-cobertura
    (後略)

な感じで入れておく。

これで、ローカルでも CodeBuild でも回帰テストが回せるようになったぞ!
docker-compose が使えるので、minio や ElasticMQ や LocalStack も動かせるのでオススメ!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?