Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support mocking of stripe outbound RPCs for unit tests #1453

Open
Kurru opened this issue Oct 8, 2022 · 6 comments
Open

Support mocking of stripe outbound RPCs for unit tests #1453

Kurru opened this issue Oct 8, 2022 · 6 comments

Comments

@Kurru
Copy link

Kurru commented Oct 8, 2022

Is your feature request related to a problem? Please describe.

When writing unit tests, there is a need to avoid outbound RPCs to another server. Today the Stripe API uses static methods and global (or request) config parameters, but there does not seem to be a way to mock the request/verify the request without running StripeMock, which is perhaps too large for a java unit test.

Describe the solution you'd like

If there was a constructor/factory based approach to constructing the stripe api, then we would be able to mock this away in our DI layer.

Today

Customer.create(customerCreateParamsObj);

Desirable alternatives

stripeFactoryObj.customerService().create(customerCreateParamsObj);

In my code I would likely provide CustomerService via DI, and then call like such:

customerService.create(customerCreateParamsObj);

This way I would be able to provide a Mockito implementation for CustomerService and setup mocks/verifications.

Describe alternatives you've considered

My solution until this is supported will be to wrap every Stripe API in a class/method and indirectly call the stripe API.

Alternatively it seems clients could use Mockito to mock static methods, though this approach is less desirable.

Additional context

No response

@programminx-askui
Copy link

programminx-askui commented Oct 9, 2022

Hello @Kurru,

I totally agree that the static implementation of the stripe API is for unit testing a pain and addition to that not the java way. I was surprised, that the stripe-node implementation, with out looking to deep to the code, creates objects for it (see https://github.com/stripe/stripe-node#usage-with-typescript).

But nevertheless, here is an example how you can mock with mockito the stripe API:

    @Test
    void createCustomer() {
        try (MockedStatic<Customer> customerMockStatic = Mockito.mockStatic(Customer.class)) {
            Customer customerMock = mock(Customer.class);
            customerMockStatic.when(() -> Customer.create(Map.of("email", "email", "metadata", Map.of("key1", "value1")))).thenReturn(customerMock);

            Customer customer = stripeBillingRepository.createCustomer("email", Map.of("key1", "value1"));

            assertEquals(customerMock, customer);
        }
    }

There is also another alternative (but not tested from me): #93 (comment)

@richardm-stripe
Copy link
Contributor

richardm-stripe commented Oct 10, 2022

Hello @Kurru, thank you for filing this.

You are right, this is a shortcoming of the library. We call your constructor/factory-based approach a "services-based architecture" and it is something we do intend to add to stripe-java, and are actively designing. We did something similar for stripe-php and stripe-java will likely be next.

I'll leave this open, mark as "future" and we'll be sure to post updates about our progress here.

If you have any advice about the design, or examples of other libraries with this architecture that you think are designed well, we appreciate any advice or input!

@Kurru
Copy link
Author

Kurru commented Oct 11, 2022

Some typed client libraries I've used recently:

Some other features you may want to consider

  • Builders for domain classes (like Customer) to enable types in tests more easily (instead of long chains of .setXYZ())
  • RPC interceptors to enable global concerns such as monitoring/tracing/logging integrations. Allow users to instrument outbound RPCs to Stripe for monitoring and debug purposes. Alerts, dashboards, AWS X-Ray etc. See GRPC and AWS client libraries for examples
  • Support async RPCs in addition to blocking interfaces (like gRPC and AWS API's support). 2nd set of APIs return CompletableFuture<YourResponseObject>

@Kurru
Copy link
Author

Kurru commented Oct 16, 2022

Additionally, the request objects don't have equality defined, which makes testing harder

@Kurru
Copy link
Author

Kurru commented Dec 18, 2022

New discoveries, timestamps exist, but don't document they are second granularity and are simple Long's. Returning java.time.Instant would be preferred.

@Kurru
Copy link
Author

Kurru commented Dec 19, 2022

Consider adding types for status's. For example, Invoice.status is a string, but really an enum. Consider providing a typed interface for this field.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants