>> Mock requests / responses for testing sounds like a good start, >> it might be nice to have the actual requests sent if test API keys >> exist - depending on how hard it is to implement with the different >> gateways. > Perhaps create a static variable like PaymentTest::$make_external_calls, > which determines whether to use external APIs or not. False by default. > I could imagine it would be frustrating if you're developing/running tests > without an internet connection.
The best way of doing this is to create a class that is a really, really thin layer around the payment gateway. It might simply be the RestfulService class. Perhaps it's assigned to $this->gateway inside the Payment class. Then you have a setter, constructor argument, or Dependency Injection framework to specify what object should be provided to this gateway. In different parts of your application you can then pass one of 3 implementations:
1. The production service 2. The test service (but still connecting to the 3. A mock object that doesn't call anything
You don't necessarily need to have 3 separate classes - the first two might be the same class but with different properties. If you like, you can use Phockito (or PHPUnit built-in mocking system, which I hate because of its verbosity) to create the 3rd one. Or you can hand-roll a mock object that does what your tests need it to.
#1 would be used for production deployment #2 would be used for manual test environments and possibly automated integration testing #3 would be used for unit tests
You might have a 4th environment, that provides a database-backed mock gateway, where that database back-end is exposed in a modeladmin. This would let you create a self-contained manual testing environment, but it means that you're testing more code that's not actually part of the production system, and it's more work. It's arguable as to whether or not this is worthwhile.
The point is that by using this dependency injection (even without a DI framework this is still dependency injection) you don't need to bake any knowledge of this stuff into your Payment class. It makes your code more testable, more maintainable, and more flexible.