简体   繁体   English

在 Python 中进行单元测试时如何模拟依赖项的响应

[英]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.我正在尝试为我创建的一些 Python 类编写单元测试。 I have created a class for wrapping s3 functionalities, and in that class I'm initializing boto3 s3 client.我创建了一个用于包装 s3 功能的类,在该类中我正在初始化 boto3 s3 客户端。

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.我想使用来自 self.s3.get_object 的模拟响应来测试方法 fetch。 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.存根实际上并没有注入到 S3_Client 中,而是对 S3 进行了真正的调用。 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.您需要让S3_Client在构造函数参数中接受客户端对象。 In this way in your tests you can create a client, stub it, then inject it to S3_Client as a parameter.通过这种方式,您可以在测试中创建一个客户端,存根它,然后将其作为参数注入S3_Client

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:如果您不想总是在类之外创建该客户端,则可以将其设为可选参数,如果没有传递,则在__init__创建一个实例:

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) .在你的测试代码中,你会说: client = S3_Client("test_bucket", self.client)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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