Python 中的模拟条纹方法用于测试
Mock Stripe Methods in Python for testing
所以我试图模拟方法中的所有 stripe web hooks
,以便我可以为它编写 Unit test
。我正在使用 mock library 来模拟条纹方法。这是我试图模拟的方法:
class AddCardView(APIView):
"""
* Add card for the customer
"""
permission_classes = (
CustomerPermission,
)
def post(self, request, format=None):
name = request.DATA.get('name', None)
cvc = request.DATA.get('cvc', None)
number = request.DATA.get('number', None)
expiry = request.DATA.get('expiry', None)
expiry_month, expiry_year = expiry.split("/")
customer_obj = request.user.contact.business.customer
customer = stripe.Customer.retrieve(customer_obj.stripe_id)
try:
card = customer.sources.create(
source={
"object": "card",
"number": number,
"exp_month": expiry_month,
"exp_year": expiry_year,
"cvc": cvc,
"name": name
}
)
# making it the default card
customer.default_source = card.id
customer.save()
except CardError as ce:
logger.error("Got CardError for customer_id={0}, CardError={1}".format(customer_obj.pk, ce.json_body))
return Response({"success": False, "error": "Failed to add card"})
else:
customer_obj.card_last_4 = card.get('last4')
customer_obj.card_kind = card.get('type', '')
customer_obj.card_fingerprint = card.get('fingerprint')
customer_obj.save()
return Response({"success": True})
这是unit testing
的方法:
@mock.patch('stripe.Customer.retrieve')
@mock.patch('stripe.Customer.create')
def test_add_card(self,create_mock,retrieve_mock):
response = {
'default_card': None,
'cards': {
"count": 0,
"data": []
}
}
# save_mock.return_value = response
create_mock.return_value = response
retrieve_mock.return_value = response
self.api_client.client.login(username = self.username, password = self.password)
res = self.api_client.post('/biz/api/auth/card/add')
print res
现在 stripe.Customer.retrieve
被正确模拟了。但是我无法模拟 customer.sources.create
。我真的坚持这个。
这是正确的做法:
@mock.patch('stripe.Customer.retrieve')
def test_add_card_failure(self, retrieve_mock):
data = {
'name': "shubham",
'cvc': 123,
'number': "4242424242424242",
'expiry': "12/23",
}
e = CardError("Card Error", "", "")
retrieve_mock.return_value.sources.create.return_value = e
self.api_client.client.login(username=self.username, password=self.password)
res = self.api_client.post('/biz/api/auth/card/add', data=data)
self.assertEqual(self.deserialize(res)['success'], False)
即使给定的答案是正确的,也有一种使用 vcrpy
更舒适的解决方案。一旦给定记录尚不存在,即会创建 cassette(记录)。当它这样做时,模拟是透明地完成的,记录将被重播。美丽的。
有一个香草金字塔应用程序,使用 py.test,我的测试现在看起来像这样:
import vcr
# here we have some FactoryBoy fixtures
from tests.fixtures import PaymentServiceProviderFactory, SSOUserFactory
def test_post_transaction(sqla_session, test_app):
# first we need a PSP and a User existent in the DB
psp = PaymentServiceProviderFactory() # type: PaymentServiceProvider
user = SSOUserFactory()
sqla_session.add(psp, user)
sqla_session.flush()
with vcr.use_cassette('tests/casettes/tests.checkout.services.transaction_test.test_post_transaction.yaml'):
# with that PSP we create a new PSPTransaction ...
res = test_app.post(url='/psps/%s/transaction' % psp.id,
params={
'token': '4711',
'amount': '12.44',
'currency': 'EUR',
})
assert 201 == res.status_code
assert 'id' in res.json_body
IMO,以下方法比其他答案更好
import unittest
import stripe
import json
from unittest.mock import patch
<b>from stripe.http_client import RequestsClient # to mock the request session</b>
stripe.api_key = "foo"
<b>stripe.default_http_client = RequestsClient() # assigning the default HTTP client</b>
null = None
false = False
true = True
charge_resp = {
"id": "ch_1FgmT3DotIke6IEFVkwh2N6Y",
"object": "charge",
"amount": 1000,
"amount_captured": 1000,
"amount_refunded": 0,
"billing_details": {
"address": {
"city": "Los Angeles",
"country": "USA",
},
"email": null,
"name": "Jerin",
"phone": null
},
"captured": true,
}
def get_customer_city_from_charge(stripe_charge_id):
# this is our function and we are writing unit-test for this function
charge_response = stripe.Charge.retrieve("foo-bar")
return <b>charge_response.billing_details.address.city</b>
class TestStringMethods(unittest.TestCase):
<b>@patch("stripe.default_http_client._session")</b>
def test_get_customer_city_from_charge(self, mock_session):
mock_response = mock_session.request.return_value
mock_response.content.decode.return_value = json.dumps(charge_resp)
mock_response.status_code = 200
<b>city_name = get_customer_city_from_charge("some_id")
self.assertEqual(city_name, "Los Angeles")</b>
if __name__ == '__main__':
unittest.main()
这种方法的优点
- 可以生成对应的class对象(这里
charge_response
变量是Charge
--(source code)的类型)
- 您可以在响应中使用 点 (.) 运算符(正如我们可以对 real条纹SDK)
- 点运算符支持深层属性
所以我试图模拟方法中的所有 stripe web hooks
,以便我可以为它编写 Unit test
。我正在使用 mock library 来模拟条纹方法。这是我试图模拟的方法:
class AddCardView(APIView):
"""
* Add card for the customer
"""
permission_classes = (
CustomerPermission,
)
def post(self, request, format=None):
name = request.DATA.get('name', None)
cvc = request.DATA.get('cvc', None)
number = request.DATA.get('number', None)
expiry = request.DATA.get('expiry', None)
expiry_month, expiry_year = expiry.split("/")
customer_obj = request.user.contact.business.customer
customer = stripe.Customer.retrieve(customer_obj.stripe_id)
try:
card = customer.sources.create(
source={
"object": "card",
"number": number,
"exp_month": expiry_month,
"exp_year": expiry_year,
"cvc": cvc,
"name": name
}
)
# making it the default card
customer.default_source = card.id
customer.save()
except CardError as ce:
logger.error("Got CardError for customer_id={0}, CardError={1}".format(customer_obj.pk, ce.json_body))
return Response({"success": False, "error": "Failed to add card"})
else:
customer_obj.card_last_4 = card.get('last4')
customer_obj.card_kind = card.get('type', '')
customer_obj.card_fingerprint = card.get('fingerprint')
customer_obj.save()
return Response({"success": True})
这是unit testing
的方法:
@mock.patch('stripe.Customer.retrieve')
@mock.patch('stripe.Customer.create')
def test_add_card(self,create_mock,retrieve_mock):
response = {
'default_card': None,
'cards': {
"count": 0,
"data": []
}
}
# save_mock.return_value = response
create_mock.return_value = response
retrieve_mock.return_value = response
self.api_client.client.login(username = self.username, password = self.password)
res = self.api_client.post('/biz/api/auth/card/add')
print res
现在 stripe.Customer.retrieve
被正确模拟了。但是我无法模拟 customer.sources.create
。我真的坚持这个。
这是正确的做法:
@mock.patch('stripe.Customer.retrieve')
def test_add_card_failure(self, retrieve_mock):
data = {
'name': "shubham",
'cvc': 123,
'number': "4242424242424242",
'expiry': "12/23",
}
e = CardError("Card Error", "", "")
retrieve_mock.return_value.sources.create.return_value = e
self.api_client.client.login(username=self.username, password=self.password)
res = self.api_client.post('/biz/api/auth/card/add', data=data)
self.assertEqual(self.deserialize(res)['success'], False)
即使给定的答案是正确的,也有一种使用 vcrpy
更舒适的解决方案。一旦给定记录尚不存在,即会创建 cassette(记录)。当它这样做时,模拟是透明地完成的,记录将被重播。美丽的。
有一个香草金字塔应用程序,使用 py.test,我的测试现在看起来像这样:
import vcr
# here we have some FactoryBoy fixtures
from tests.fixtures import PaymentServiceProviderFactory, SSOUserFactory
def test_post_transaction(sqla_session, test_app):
# first we need a PSP and a User existent in the DB
psp = PaymentServiceProviderFactory() # type: PaymentServiceProvider
user = SSOUserFactory()
sqla_session.add(psp, user)
sqla_session.flush()
with vcr.use_cassette('tests/casettes/tests.checkout.services.transaction_test.test_post_transaction.yaml'):
# with that PSP we create a new PSPTransaction ...
res = test_app.post(url='/psps/%s/transaction' % psp.id,
params={
'token': '4711',
'amount': '12.44',
'currency': 'EUR',
})
assert 201 == res.status_code
assert 'id' in res.json_body
IMO,以下方法比其他答案更好
import unittest
import stripe
import json
from unittest.mock import patch
<b>from stripe.http_client import RequestsClient # to mock the request session</b>
stripe.api_key = "foo"
<b>stripe.default_http_client = RequestsClient() # assigning the default HTTP client</b>
null = None
false = False
true = True
charge_resp = {
"id": "ch_1FgmT3DotIke6IEFVkwh2N6Y",
"object": "charge",
"amount": 1000,
"amount_captured": 1000,
"amount_refunded": 0,
"billing_details": {
"address": {
"city": "Los Angeles",
"country": "USA",
},
"email": null,
"name": "Jerin",
"phone": null
},
"captured": true,
}
def get_customer_city_from_charge(stripe_charge_id):
# this is our function and we are writing unit-test for this function
charge_response = stripe.Charge.retrieve("foo-bar")
return <b>charge_response.billing_details.address.city</b>
class TestStringMethods(unittest.TestCase):
<b>@patch("stripe.default_http_client._session")</b>
def test_get_customer_city_from_charge(self, mock_session):
mock_response = mock_session.request.return_value
mock_response.content.decode.return_value = json.dumps(charge_resp)
mock_response.status_code = 200
<b>city_name = get_customer_city_from_charge("some_id")
self.assertEqual(city_name, "Los Angeles")</b>
if __name__ == '__main__':
unittest.main()
这种方法的优点
- 可以生成对应的class对象(这里
charge_response
变量是Charge
--(source code)的类型) - 您可以在响应中使用 点 (.) 运算符(正如我们可以对 real条纹SDK)
- 点运算符支持深层属性