Home > Software design >  Mock testing a python functionality for S3 Upload
Mock testing a python functionality for S3 Upload

Time:04-13

I would like to mock the below written functionality. For that, I am not sure about adding unit test for the same. Any advise on writing possiblt unit tests without using unittest library? Thank you so much!

def file_upload(self, upload_file_bucket, file_name, file_path):
        if os.path.exists(file_path):
            with open(file_path, 'r') as f:
                xml = f.read()
        else:
            logging.error("File '%s' does not exist." % file_path)
            tools.exit_gracefully(botocore.log)
        try:
            conn = boto3.session.Session(profile_name=aws_prof_dev_qa)
            s3 = conn.resource('s3')
            object = s3.Object(upload_file_bucket, file_name)
            result = object.put(Body=xml)
            res = result.get('ResponseMetadata')
            if res.get('HTTPStatusCode') == 200:
                logging.info('File Uploaded Successfully')
            else:
                logging.info('File Not Uploaded Successfully')
            return res
        except ClientError as e:
            logging.error(e)

CodePudding user response:

You can write robust, end-to-end tests using moto.

Moto is the best practice for testing boto. It simulates boto in your local machine, creating buckets locally so you can have complete end-to-end tests.

Here is some example code for your method (I changed your code to use the profile name 'aws_prof_dev_qa'). I used pytest fixtures to organize my code, but that is not mandatory:

@pytest.fixture(scope='session')
def aws_credentials():
    """Mocked AWS Credentials for moto."""
    os.environ['AWS_ACCESS_KEY_ID'] = 'testing'
    os.environ['AWS_SECRET_ACCESS_KEY'] = 'testing'
    os.environ['AWS_SECURITY_TOKEN'] = 'testing'
    os.environ['AWS_SESSION_TOKEN'] = 'testing'
    os.environ['AWS_DEFAULT_REGION'] = 'us-east-1'

    try:
        tmp = NamedTemporaryFile(delete=False)
        # you many need to change 'aws_prof_dev_qa' to be your profile name
        tmp.write(b"""[aws_prof_dev_qa]
aws_access_key_id = testing
aws_secret_access_key = testing""")
        tmp.close()
        os.environ['AWS_SHARED_CREDENTIALS_FILE'] = str(tmp.name)
        yield
    finally:
        os.unlink(tmp.name)


@pytest.fixture(scope='function')
def empty_bucket(aws_credentials):
    moto_fake = moto.mock_s3()
    try:
        moto_fake.start()
        conn = boto3.resource('s3')
        conn.create_bucket(Bucket="MY_BUCKET")  # or the name of the bucket you use
        yield conn
    finally:
        moto_fake.stop()


def test_file_upload(empty_bucket):
    with NamedTemporaryFile() as tmp:
        tmp.write(b'Hi')
        file_name = pathlib.Path(tmp.name).name

        result = file_upload("MY_BUCKET", file_name, tmp.name)

        assert result.get('HTTPStatusCode') == 200

For more details about why moto is better than just mocking, see my lecture.

  • Related