模拟boto3要求进行单元测试

时间:2017-12-21 18:41:25

标签: python unit-testing amazon-web-services mocking

我们有一个看起来像这样的课程:

import boto3
import json
import time
import sys

def stop_instances_python(instanceId):
    ec2_client = boto3.client('ec2', region_name='us-east-1')
    while True:
        try:
            ec2_client.stop_instances(InstanceIds=[instanceId])
            print "EC2 instance: " + instanceId + " stopped"
            break
        except Exception, e:
            if ('RequestLimitExceeded' in str(e)):
                print "Request throttled. Sleeping for 15s"
                time.sleep(15)
                res = ec2_client.describe_instances(InstanceIds=[instanceId])
                print "instance state: " + res['Reservations'][0]['Instances'][0]['State']['Name']
                try:
                    ec2_client.stop_instances(InstanceIds=[instanceId])
                    print "EC2 instance: " + instanceId + " stopped" ## Unable to test this
                except Exception, e:
                    if ('RequestLimitExceeded' in str(e)):
                        print "Request throttled again. Sleeping for 10s"
                        time.sleep(10)
                    else:
                        print str(e)
                        sys.exit(1)
            else:
                print str(e)
                sys.exit(1)

我们想为这个类编写单元测试用例。我们使用motomock来测试大多数行。我们无法通过评论测试该行:# Unable to test this。这是因为每次发送停止请求时,都会受到限制。我们的测试用例文件如下所示:

from moto import mock_ec2
from moto import mock_sts
from mock import patch
import botocore
import boto3
import mock
from botocore.exceptions import ClientError

orig = botocore.client.BaseClient._make_api_call

def mock_throttling(self, operation_name, kwarg):
    if operation_name == 'StopInstances':
        parsed_response = {
            'Error': {'Code': '500', 'Message': 'RequestLimitExceeded'}}
        raise ClientError(parsed_response, operation_name)
    return orig(self, operation_name, kwarg)

def mock_throttling_side_effect(self, operation_name, kwarg):
    mock_api = mock.Mock()
    parsed_response = {'Error': {'Code': '500', 'Message': 'RequestLimitExceeded'}}
    if operation_name == 'StopInstances':
        mock_api.side_effect = [
            ClientError(parsed_response, operation_name),
            orig(self, operation_name, kwarg)
        ]
        mock_api()       
    return orig(self, operation_name, kwarg)

class TestEC2StopInstances:
    @mock_ec2
    @mock_sts
    @patch('time.sleep', return_value=None)
    def test_ec2_lambda_handler(self, patched_time_sleep):
        from StopInstancesPython import stop_instances_python
        client = boto3.client('ec2', region_name='us-east-1')
        response = client.run_instances(ImageId='ami-1234567', MinCount=1, MaxCount=1)
        instanceId = response['Instances'][0]['InstanceId']
        with patch(
                'botocore.client.BaseClient._make_api_call',
                new=mock_throttling_side_effect):
            stop_instances_python(instanceId)

我们尝试同时使用mock_throttlingmock_throttling_side_effect。当我们使用mock_throttling时,StopInstances API始终会抛出RequestLimitExceeded异常(这是预期的行为)。 当我们使用mock_throttling_side_effect时,实例会在第一个StopInstances API调用中停止,并且还会抛出RequestLimitExceeded异常并继续执行无限循环。

有人可以指导我们如何测试此代码的所有行吗?

0 个答案:

没有答案