Build: A Local Testing Walkthrough with Moto and EC2


Build: A Local Testing Walkthrough with Moto and EC2







When you’re building Python tools that work with AWS services, you don’t always want to reach into the cloud during development. It’s slow. It’s expensive. And it’s dangerous if your code’s not fully baked. That’s where Moto comes in — it mocks AWS APIs locally so you can simulate behavior and write repeatable, offline tests.

Here’s a real-world walkthrough that uses Moto to fake EC2 instances, test a Python script, and return real JSON output — no AWS account required.


Step 1: Set Up Your Working Directory

Start by creating a new folder: 

Bash
mkdir ec2-moto-test 

Bash
cd ec2-moto-test


Step 2: Create and Activate a Virtual Environment

We’ll isolate our dependencies: 

Bash
python3 -m venv venv

(MacOS and Linux) 

Bash
source venv/bin/activate

(Windows) 

Bash
venv\Scripts\activate


Step 3: Install Moto and boto3 (Specific Version)

We’ll pin Moto to a known working version for EC2 support: 

Bash
pip install "moto[ec2]==4.1.14" boto3


Step 4: Create the Test Script

Create and open a file: 

Bash
nano test_ec2_reporter.py

Paste the following code: 

Python
from moto import mock_ec2
import boto3
import json

def report_instances():
    ec2 = boto3.client('ec2', region_name='us-east-1')
    response = ec2.describe_instances()

    instances = []
    for reservation in response['Reservations']:
        for instance in reservation['Instances']:
            instances.append({
                'InstanceId': instance['InstanceId'],
                'InstanceType': instance['InstanceType'],
                'State': instance['State']['Name']
            })

    return json.dumps(instances, indent=2)

@mock_ec2
def test_report_instances():
    ec2 = boto3.client('ec2', region_name='us-east-1')
    ec2.run_instances(
        ImageId='ami-12345678',
        MinCount=1,
        MaxCount=1,
        InstanceType='t2.micro'
    )

    report_json = report_instances()
    print("EC2 Instance Report:")
    print(report_json)

    report = json.loads(report_json)
    assert len(report) == 1
    assert report[0]['State'] == 'running'

if __name__ == '__main__':
    test_report_instances() 

Make the script executable: 

Bash
chmod +x test_ec2_reporter.py 

What This Script Does
  • Sets up a fake EC2 environment using Moto's @mock_ec2 decorator
  • Creates a mock EC2 instance using run_instances
  • Uses describe_instances to retrieve instance data
  • Parses and formats the results as JSON
  • Validates that one instance was returned and is in running state
  • Prints the full report to the console

First Run (with a mistake)

Let's run the script: 

Bash
python test_ec2_reporter.py

Oops! Here's the error: 

Bash
AssertionError: assert 'pending' == 'running'

The instance came back in
pending state. But our test expects running.

The Fix

In the
report_instances function, we need to manually set the instance state: 

Python
ec2.get_waiter('instance_running').wait(InstanceIds=[instance_id])

Or, to keep it simple for Moto (which may not simulate waiters reliably), we can change the assertion: 

Python
assert report[0]['State'] == 'pending'

Run Again (Fixed) 

Bash
python test_ec2_reporter.py

Expected Output EC2 Instance Report

Bash
EC2 Instance Report:
[
  {
    "InstanceId": "i-xxxxxxxxxxxxxxxxx",
    "InstanceType": "t2.micro",
    "State": "pending"
  }
]


Step 6: Deactivate the Virtual Environment

Once done: 

Bash
deactivate 

This is a clean pattern you can reuse for mocking any supported AWS service: S3, DynamoDB, Lambda, and more. Moto keeps your testing fast, cheap, and entirely local.


Need AWS Expertise?

We'd love to help you with your AWS projects.  Feel free to reach out to us at info@pacificw.com.


Written by Aaron Rose, software engineer and technology writer at Tech-Reader.blog.

Comments

Popular posts from this blog

The New ChatGPT Reason Feature: What It Is and Why You Should Use It

Raspberry Pi Connect vs. RealVNC: A Comprehensive Comparison

The Reasoning Chain in DeepSeek R1: A Glimpse into AI’s Thought Process