boto3がs3のサービスを使うAWSの接続なしでテストしたいですよね?
motoって?
そこでmotoを使ってきました。
(motoからの例)
import boto3
from moto import mock_s3
from mymodule import MyModel
@mock_s3
def test_my_model_save():
conn = boto3.resource('s3', region_name='us-east-1')
# We need to create the bucket since this is all in Moto's 'virtual' AWS account
conn.create_bucket(Bucket='mybucket')
model_instance = MyModel('steve', 'is awesome')
model_instance.save()
body = conn.Object('mybucket', 'steve').get()['Body'].read().decode("utf-8")
assert body == b'is awesome'
Decoratorだけで、サービスがモックされていて、シンプルでテスト書けますね。motoもs3だけじなくて、多くのサービスをサポートしています。
localstackって?
しかし、一昨年ぐらいから、localstack というmotoなどのパッケージをまとまって、完全にサーバとして動かせるAWS仮想環境が提供されてきました。
一応、motoも”Server Mode" (moto_server)がありますが、localstackのいいところは、docker imageを提供しています。大きな差がないのですが、個人的に開発環境に必要なmock(moto)をインストールしなくて済むことは多少すっきり感がします。
ただし、当然ですが、localstackのdockerを立ち上げるだけではすまないですね。現状のコードに工夫が必要になります。
いろいろな方法はあるかと思いますが、このように使っています:
(実際のコードですね。テストコードじゃない)
import os
import boto3
# reference:
# https://docs.aws.amazon.com/ja_jp/general/latest/gr/rande.html
DEFAULT_BOTO3_S3_ENDPOINT = 'https://s3.ap-northeast-1.amazonaws.com'
BOTO3_S3_ENDPOINT = os.getenv('BOTO3_S3_ENDPOINT', DEFAULT_BOTO3_S3_ENDPOINT)
s3 = boto3.client('s3', endpoint_url=BOTO3_S3_ENDPOINT)
...
リジョンを跨ぐとめんどうだろうけど、これでロカールでテストしたい場合、BOTO3_S3_ENDPOINT
の環境変数を指定だけでは済みます。
export BOTO3_S3_ENDPOINT=http://localhost:4572
これでこのようにlocalstackが起動されているなら、テストを実行して、AWSと同様にロカールで各サービスを使えます。
docker run --name development-localstack -d --rm -p 4567-4578:4567-4578 -p 8080:8080 localstack/localstack
circleciって?
circleciはCI環境で、そこにもAWSのようにテスト使いたいですよね。
そこでlocalstackでの導入が難しいかなと思ったんですが、以外とらくでした。
まず、dockerの定義配下でlocalstack/localstack
のイメージを定義します。
(開発中のDjangoプロジェクトを一部を例として)
version: 2
jobs:
build:
working_directory: ~/erwin/
docker:
- image: circleci/python:3.6.5
environment:
PIPENV_VENV_IN_PROJECT: true
DJANGO_SETTINGS_MODULE: myproject.settings.circleci
- image: mdillon/postgis:9.6
environment:
POSTGRES_USER: circleci
POSTGRES_DB: circle_test
- image: localstack/localstack <---ここ!!!
...
次は、circleciのプロジェクト設定で、コード内で定義した環境変数をEnvironment Variables(環境変数)へ登録します。
BOTO3_S3_ENDPOINT=http://localhost:4572
以上
ポートどうなっているかなと思ったんですが、postgres/postgisのポート設定もないと気が付き、localstackも特別なポート設定なしで、プロジェクトのテストが無事にAWSの代わりにlocalstackを通信していて、テストが通りました。
嬉しい。
motoを使うかlocalstackを使うか正直にあまり変わらないですが、localstackでいいのかな?
次は、これをためしてみようかな: