boto3からEC2へのアクセスをmotoでモックしてみる

2022.07.29

こんにちは、muroです。AWS運用かんたん自動化ツール「opswitch」の開発・運用を担当しています。opswitchはboto3をがんがん使ってAWSを操作します。今回はboto3のモックライブラリ「moto」を利用して、EC2インスタンスの停止をテストしてみます。

なお、本記事の執筆にあたっては以下の記事を参考にしています。こちらもどうぞご覧ください。

boto3からSQSへのアクセスをmotoでモックしてみる

はじめに

今回のテストに使用した環境は以下の通りです。

環境 バージョン
Python 3.9.13
boto3 1.23.3
moto 3.1.9
pytest 7.1.2

またテストプロジェクトの構成は以下の通りです。

.
├── main.py
└── test_main.py

やってみる

テスト対象コード

指定されたEC2インスタンスを停止するだけの関数です。

main.py

import boto3


def stop_instances(instance_ids):
    ec2 = boto3.client('ec2')
    ec2.stop_instances(
        InstanceIds=instance_ids
    )

存在するEC2インスタンスのIDを渡して実行すると、実際に停止されることを確認できます。

テストコード

テストでmotoを利用するには、各AWSサービスに応じたモックを用意します。motoからEC2に対応するmock_ec2をインポートし、テスト関数にデコレータとして@mock_ec2と記述するだけです。boto3を通じてEC2を操作しますが、このテスト関数の実行においては、モック内にあるAMIを利用し、モック内でインスタンスの起動及び停止を行います。AWS上にEC2インスタンスを立てることはありません。

test_main.py

import boto3
from moto import mock_ec2
import main


@mock_ec2
def test_stop_instance():
    # 期待するインスタンス数を設定します。
    expected_instances_number = 10

    # 期待するインスタンス数の分だけインスタンスを起動します。
    ec2 = boto3.client('ec2')
    images = ec2.describe_images()['Images']
    response = ec2.run_instances(
        ImageId=images[0]['ImageId'],
        MinCount=expected_instances_number,
        MaxCount=expected_instances_number,
    )
    input_instance_ids = [x['InstanceId'] for x in response['Instances']]

    # インスタンス停止を実行します。
    main.stop_instances(input_instance_ids)

    # インスタンスが停止されたかどうかテストします。
    for instance_id in input_instance_ids:
        response = ec2.describe_instances(
            InstanceIds=[instance_id]
        )
        instances = response['Reservations'][0]['Instances'][0]
        assert(instances['State']['Name'] == 'stopped')

テスト実行

それではテストを実行してみます。

python -m pytest
============================== test session starts ===============================
platform linux -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0
rootdir: /home/ユーザー/プロジェクト
collected 1 item

test_main.py .                                                             [100%]

=============================== 1 passed in 1.01s ================================

私のPC上では、わずか1秒で10台のインスタンス起動から停止まで完了しました。

まとめ

boto3を使うアプリケーションに対して、motoを利用することで実際のAWSリソースを操作することなく高速にテストできました。テスト環境としてあらかじめAWS上にリソースを立てておく必要がないのはもちろん、リソースの止め忘れや削除し忘れの心配もありません。またboto3のリクエストパラメータやレスポンスの検証を手元で高速にできるため、アプリケーションの設計やAWSの仕様調査・学習にも大変便利なツールです。以上、ご参考になりましたら幸いです。