moto单元测试EC2报'NoneType' object has no attribute 'id'错误
Moto mock EC2单元测试实例查询为空、属性报错问题修复
问题根因
- Mock资源区域隔离:moto对AWS服务的mock是按区域维度做资源隔离的,测试代码中查询实例用的客户端硬编码了
eu-central-1区域,如果业务代码全局变量REGION_NAME不是该值,业务客户端和测试查询客户端操作的是完全独立的两套mock资源池,自然查询不到创建的实例。 - Mock环境缺少前置依赖资源:真实AWS账号下已经存在的AMI、密钥对、安全组,在moto初始化的空白mock环境中默认不存在。直接在
run_instances接口传入不存在的IMAGE_ID、KEY_NAME、SECURITY_GROUP_ID会导致接口调用失败,不会生成任何EC2实例。此时强行从返回结果取["Instances"][0]会拿到None值,后续代码访问该对象的id属性就会触发'NoneType' object has no attribute 'id'报错。 - 业务代码逻辑缺陷:
launchInstances方法传入count=2时,run_instances返回的Instances数组包含2个实例对象,当前代码直接取[0]仅获取第一个实例,和传入的创建数量不匹配,后续实例状态维护会出现遗漏。
修复方案
1. 调整单元测试逻辑,统一区域、提前创建依赖资源
测试用例中不要硬编码区域,直接复用业务代码的区域常量,在mock环境中提前创建好run_instances需要依赖的密钥对、安全组资源:
import unittest import boto3 from moto import mock_ec2 import aws_manager # 导入业务代码的配置常量,保证配置统一 from aws_manager import REGION_NAME, KEY_NAME @mock_ec2 class TestAwsManager(unittest.TestCase): def test_launchInstances(self): # 初始化和业务同区域的EC2客户端 mock_ec2_client = boto3.client('ec2', region_name=REGION_NAME) # 提前创建mock环境依赖资源 mock_ec2_client.create_key_pair(KeyName=KEY_NAME) sg_resp = mock_ec2_client.create_security_group( GroupName='test-sg', Description='unit test security group' ) # 替换业务代码中硬编码的安全组ID为mock生成的ID aws_manager.SECURITY_GROUP_ID = sg_resp['GroupId'] # moto默认提供可直接使用的测试AMI,无需手动注册,直接用业务配置的IMAGE_ID即可 # 执行业务逻辑 manager = aws_manager.aws_manager() manager.launchInstances(2) # 验证创建结果 instances_resp = mock_ec2_client.describe_instances() self.assertEqual(len(instances_resp['Reservations']), 1) self.assertEqual(len(instances_resp['Reservations'][0]['Instances']), 2)
2. 修正业务代码的实例创建逻辑
不要只取返回数组的第一个实例,要处理所有创建成功的实例,维护到实例列表中:
def launchInstances(self, count: int): run_resp = self.ec2.run_instances( ImageId=IMAGE_ID, MinCount=count, MaxCount=count, InstanceType=INSTANCE_TYPE, KeyName=KEY_NAME, SecurityGroupIds=[SECURITY_GROUP_ID] ) created_instances = run_resp["Instances"] # 将所有创建的实例加入维护列表 self.running_instances.extend(created_instances) return created_instances
注意:不要在业务代码中硬编码生产环境的资源ID、区域等配置,最好抽成可传入的配置项,单元测试时直接传入mock环境生成的测试资源配置,避免环境配置不匹配导致的测试失败。
内容的提问来源于stack exchange,提问作者codedor
相关产品推荐
相关产品推荐

