Since one of the main goals of implementing an integrated payment system is to make it simple to quickly onboard a new payment provider, having shared interfaces for payment actions also demands easier wiring of the functionality of each payment action for a specific API.
It would really suck for a developer to have to go to every call site where a particular payment action is implemented or referenced and add some kind of switch statement, or if else and check the payment provider that is to be used.
The integrated payment system will need to be able interact with the USA ePay REST API in order to process different types of payment operations.
In the beginning of the project, I established that each payment operation is represented by an interface and it would be the responbility of the payment provider to describe the implementation for each. This is fundamentally different than having a payment provider have to implement all payment operations.
The main reasons behind this are the payment provider:
To implement a payment operation, the interface will describe a command handler which will receive a message made up by the fields necessary to process the payment operation. The output of the command handler will be an additional interface describing the generalized output of the command (authorization code, error code etc).
What's important here is that the fields and their types in the interfaces are not to be tied to any particular payment providers. This is critical to making sure each of the payment actions are as generic as possible.
As an example consider "CreditCardTokenSale", the the first payment operation I implemented. This operation closely mimics that of an actual credit card sale except for the fact that no PCI SAD data is ever used.
The message is made up of fields such as a billing address, some token string representing a credit card saved by the payment provider, and additional information about the sale (payment amount, cardholder name etc).
Since I'm free to write any implementation I like inside the command handler assigned to the interface, the payment operation can be made up by any combination of API operations.
Given that these command handlers don't have any relationship with the interfaces for the messages they receive and produce, I can inject any dependencies into them I choose such as delegate methods for the API operations. This way I can decouple the actual command handler implementation from my API implementation allowing for better unit testing.
Interacting with live payment providers is great, but what happens when a service is down or an integration isn't ready? Being able to use an application disconnected from any payment provider has the potential to provide huge productivity gains.
Are there times when testing where it's not necessary to even process a payment? Sure.
If I'm doing a test of the UI, I really don't care to reach out to all of the 3rd party integrations, maybe incur API quota usages, and especially risk errors if the API is down or in a bad state.
There might be a configuration possible where the entire payment portion is bypassed and I just want to put the system into a state where a particular domain has the payment information available to continue on. In this scenario, maybe I've called a dummy payment provider to give me a fake payload to satisfy domain payment requirements so that it can continue.
The reasons are numerous but being able to unplug a live payment provider from a system has several advantages and makes the life of a developer much easier. As a tester, sometimes it might not be critical that a test needs to make an actual payment and that the payment step is just part of the setup path. Another time a tester might benefit from this is when the payment provider is down, and testing is still able to progress in light of the outage. Being able to switch it out certainly helps continuous integration to continue and prevent outages from causing delays in production.