简体   繁体   中英

How to mock a dependency's response when unit-testing in Python

I am trying to write unit test for some of Python classes I have created. I have created a class for wrapping s3 functionalities, and in that class I'm initializing boto3 s3 client.

class S3_Client:

    def __init__(self, bucket_name):
        self.s3 = boto3.client("s3", aws_access_key_id=e_config["aws_access_key"], aws_secret_access_key=e_config["aws_secret_key"])
        self.bucket_name = bucket_name

    def fetch(self, key):
        response = self.s3.get_object(Bucket=self.bucket_name, Key=key)

        return self.__prepare_file_info(response, key) # return formatted response 

I would like to test method fetch with mocked response from self.s3.get_object. This is my test class:

import unittest
from .aws_s3_service import S3_Client # class I want to test
import boto3
from botocore.stub import Stubber

class TestS3_Client(unittest.TestCase):

    def setUp(self):
        self.client = boto3.client('s3')
        self.stubber = Stubber(self.client)

    def test_fetch(self):
        get_object_response = {...} # hardcoded response
        self.stubber.add_response('get_object', get_object_response, {"Bucket": "test_bucket", "Key": "path/to/file/test_file.txt"})

        with self.stubber:
            client = S3_Client("test_bucket")
            result = client.fetch("path/to/file/test_file.txt")

The stubber is not actually injected into S3_Client, a real call to S3 is made. How do I inject the stubber? Any help is appreciated, thanks.

You need to make S3_Client accept a client object in a constructor argument. In this way in your tests you can create a client, stub it, then inject it to S3_Client as a parameter.

If you don't like having to always create that client outside of the class, you can make it an optional argument, and create an instance in __init__ if none was passed:

class S3_Client:
    def __init__(self, bucket_name, s3=None):
        if s3 is None:
            self.s3 = boto3.client("s3", aws_access_key_id=e_config["aws_access_key"],                 aws_secret_access_key=e_config["aws_secret_key"])
        else:
            self.s3 = s3
        self.bucket_name = bucket_name
    ...

In the code of your test you would then say: client = S3_Client("test_bucket", self.client) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM