sahaaari
sahaaari

Reputation: 11

How mock stripe in Django unit test

We used stripe for the payment system. Imagine a user is doing different things in our system and for each part, he has to pay. We send these payments to Stripe by calling:

stripe.InvoiceItem.create()

Then we create and finalize the invoice for him by calling:

invoice=stripe.Invoice.create()
stripe.Invoice.finalize_invoice(invoice.id)

So if the user has to pay for 3 items:

item1 = 1
item2 = 2
item3 = 3

The finalize_invoice will have an id, total, ...., and:

total = 6

To test if all items are sending the correct amount to Stripe, I'd like to check the total.

In order to test our payment system, I had to mock Stripe, but the Stripe invoice total would always be zero.

I mocked stripe.InvoiceItem.create and stripe.Invoice.finalize_invoice and stripe.Invoice.create like this:

@patch("app_name.models.stripe.InvoiceItem.create")
@patch("app_name.models.stripe.Invoice.finalize_invoice")
@patch("app_name.models.stripe.Invoice.create")
def test_method(
    self,
    mock_create,
    mock_finalize,
    mock_invoice_item,
):
    response = MagicMock()
    # api_key and stripe_account from this link https://stripe.com/docs/api/connected_accounts
    response.api_key = "sk_test_MSc53AbTknQXPy"
    response.stripe_account = "acct_1032D82eZvKYlo2C"  # Stripe account ID
    # last version here https://stripe.com/docs/upgrades
    response.stripe_version = "2022-08-01" 
    mock_invoice_item.return_value = response

    response = MagicMock()
    response.total = 20
    response.invoice_pdf = "https://google.com"
    response.id = "sk_test_MSc53AbTknQXPy"
    mock_create.return_value = response
    mock_finalize.return_value = response.id

Stripe might have a mocking feature. Stripe-mock was not clear to me how to use it in unit tests.

Upvotes: 0

Views: 1288

Answers (2)

jnns
jnns

Reputation: 5634

Stripe API responses can be mocked conveniently using unittest.mock, dictionaries and stripe.convert_to_stripe_object:

@patch("app_name.models.stripe.Invoice.retrieve")
def test_method(self, mock_retrieve):

    data = {
        "id": "sk_test_1234",
        "total": 20,
        "invoice_pdf": "https://example.com/invoice.pdf",
    }

    mock_retrieve.return_value = stripe.convert_to_object(
        data, 
        stripe_version="2022-08-01"
    )

Upvotes: 0

Tarzan
Tarzan

Reputation: 1077

I really don't know how you are mocking the different Stripe functions in order to pinpoint the issue with the the invoice total cost.

If you're thinking of using stripe-mock, I guess the best way to handle unit testing is to do so in an agnostic way (regardless of the stack), by running the stripe-mock Docker as described in the github Readme and create a proxy that will route any API call to the Docker URL instead of the actual API URL (https://api.stripe.com). This will allow you to do unit testing locally on your machine and even with your preferred CI/CD.

With that being said, please bear in mind that there are some known limitations described in the Readme doc.

Upvotes: 0

Related Questions