Putting Credit Card Processing to the Test
(Tue May 17, 2005) [/Rails] #
James and I just started helping a client transition their e-commerce web application from Java to Rails. Being sharp folks, they know that the integration points to external systems pose the highest risk. So we have a prioritized list of tasks, starting with the most important: credit card processing.
Why start here? Well, their Java web application handles credit card transactions using VeriSign's Payflow Pro Java SDK. (Sorry, no Ruby SDK.) And while VeriSign has client-side C libraries that we could call from Ruby, the Payflow Pro library isn't supported on Mac OS X, which happens to be the deployment platform of choice for this client. Worse yet, it turns out there's special sauce in the client-side libraries, and the source isn't available.
We ended up writing a thin Ruby wrapper around the Java library. Request parameters go in, are subjected to validation, and then are packaged for transport down the pipe. When the response comes back, it's pulled apart into attributes of the wrapper class. By passing in test requests and mocking responses, we were able to write a comprehensive set of unit tests without ever hitting the VeriSign test server.
But unit testing only takes you so far. After getting confidence in the Ruby wrapper, we needed to run end-to-end tests. The last time I integrated with a credit card processing gateway (several years ago), functional testing wasn't very rewarding. If you were lucky, you got a test server and a test credit card number to play with.
I was pleasantly surprised to find that Payflow Pro takes testing seriously. In fact, the Developer's Guide has a whole chapter dedicated to poking and prodding the VeriSign test server to generate specific result codes. For example, if you want to make the gateway decline a card, you simply submit a transaction amount greater than $2001 while in test mode. This was a real boon in helping us quickly put together a generous suite of functional tests.
The task turned out to be fairly straightforward and we've already checked it off the list. But it was important to put it behind us early because there was an unknown. However, it begs the question: How might other systems I'm integrating with be made more testable?
