在我正在处理的项目中,我们使用条带,但我们需要在测试中模拟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。
我做错了什么?