Build: Local EC2 Testing with Moto and Python



Build: Local EC2 Testing with Moto and Python







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

Then navigate into it: 

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) Now activate the virtual environment:

Bash
source venv/bin/activate 

(Windows) You’d use: 

Bash
venv\Scripts\activate


Step 3: Install Moto and boto3 (Specific Version)


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

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

This version ensures EC2 mocking works cleanly with the classic
mock_ec2 import path.


Step 4: Create the Test Script

Create a file named test_ec2_reporter.py

Bash
nano test_ec2_reporter.py

Paste the following code: 

Python
from moto import mock_ec2
import boto3
import json

# This function simulates your EC2 reporting logic
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')

    # Create a fake EC2 instance inside the mock environment
    ec2.run_instances(
        ImageId='ami-12345678',
        MinCount=1,
        MaxCount=1,
        InstanceType='t2.micro'
    )

    # Run the reporting logic against the mocked instance
    report_json = report_instances()
    print("EC2 Instance Report:")
    print(report_json)

    # Validate result
    report = json.loads(report_json)
    assert len(report) == 1
    assert report[0]['State'] == 'running'  # Default state in Moto

# Execute test manually
if __name__ == '__main__':
    test_report_instances()

Now ensure that the Python script is executable:

Bash
chmod +x test_ec2_reporter.py 


Step 5: Run the Script


Now test it locally: 

Bash
python test_ec2_reporter.py 

You’ll see: 

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


Step 6: Deactivate the Virtual Environment

Run this command the exit the virtual environment: 

Bash
deactivate


Final Thoughts

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. When you’re ready to step into real cloud behavior — IAM, networking, multi-service flows — that’s when you graduate to LocalStack Pro.

And yes, we’ll go wild with pytest and unittest soon. But for today, this is real progress.


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