ContextDecorator不会在__exit__上恢复模拟对象

时间:2018-03-12 23:19:34

标签: python mocking

在我正在处理的项目中,我们使用条带,但我们需要在测试中模拟API调用。

我写了一个继承自contextlib.ContextDecorator的类,所以我可以将它用作装饰器和上下文管理器。这是代码:

class mock_stripe(ContextDecorator):
    """Mock Stripe API calls.

    This class will be either working as a function decorator or as a
    context manager that will mock calls to the Stripe API, so there won't
    be any HTTP Request nor possible flakyness if the Stripe test API is
    down.

    """

    def __init__(self, customer=None, source=None,
                 retrieved_charge=None):
        """Initialize the context with objects to return upon mocked calls.

        If none of the arguments are provided, they will receive default
        values.

        Args:
            customer: The stripe customer to return.
            source: The stripe source to return.
            charge: The stripe charge to return.
            retrieved_charge: The stripe retrieved charge to return.
        """
        self.customer = customer
        self.source = source
        self.retrieved_charge = retrieved_charge

        self.pending_charge = MagicMock()
        self.pending_charge.status = 'pending'

        self.charge_state = 0

        if self.customer is None:
            self._create_default_customer()

        if self.source is None:
            self._create_default_source()

        if self.retrieved_charge is None:
            self._create_default_retrieved_charge()

    def _create_default_customer(self):
        self.customer = MagicMock()
        self.customer.stripe_customer_token = "token"
        self.customer.get_full_name = lambda: "Georges Abitbol"
        self.customer.email = "georges.abitbol@example.com"
        self.customer.number = "0123456789"
        self.customer.customer_id = "1"
        self.customer.id = "1"
        self.customer.source.id = "2"

    def _create_default_source(self):
        self.source = MagicMock()
        self.source.id = "2"
        self.source.customer_id = "1"
        self.source.sepa_debit.mandate_reference = "3"
        self.source.sepa_debit.mandate_url = "http://foo.bar/baz"

    def _create_default_retrieved_charge(self):
        self.retrieved_charge = MagicMock()
        self.retrieved_charge.status = 'succeeded'

    def __enter__(self):
        self.exit_stack = ExitStack()
        customer_create = self.exit_stack.enter_context(
            patch('stripe.Customer.create'))

        customer_retrieve = self.exit_stack.enter_context(
            patch('stripe.Customer.retrieve'))

        sources_create = self.exit_stack.enter_context(
            patch('stripe.Source.create'))

        charge_create = self.exit_stack.enter_context(
            patch('stripe.Charge.create'))

        charge_retrieve = self.exit_stack.enter_context(
            patch('stripe.Charge.retrieve'))

        customer_create.return_value = self.customer
        customer_retrieve.return_value = self.customer
        sources_create.return_value = self.source
        charge_create.return_value = self.pending_charge
        charge_retrieve.return_value = self.retrieved_charge

        return self

    def __exit__(self, *exc):
        self.exit_stack.pop_all()
        return False

我模拟了patch函数,但__exit__方法中的代码无法恢复已修补的函数,并且在其他测试期间它们仍然被模拟,我不想这样做happend。

我做错了什么?

0 个答案:

没有答案