Harry's Engineering

Harry's
Engineering
Blog

15.04.14

Mock Authorize.net CIM Gateway for ActiveMerchant

By: Andy O'Neill

Harry’s is currently using the venerable Authorize.net as our payment gateway for ecommerce. We don’t want to host our own credit card data, so we are using the Authorize.net “Customer Information Manager” (CIM) API to store user billing profiles securely on their servers, tied to their Harry’s accounts with a customer profile id.

Too slow for TDD

We’re a Rails shop so we are using the marvellous ActiveMerchant by Shopify to wrap our interactions with the payment provider, but because we are using the CIM API we can’t use the nifty BogusGateway they provide for testing the standard gateway interface. When I joined Harry’s we were running our unit tests against the Authorize.net sandbox server. As we filled out the test suite and added more developers, it became clear that creating a sandbox customer profile at Authorize.net for each test was responsible for about 50% of our test time.

In November I set out to speed things up by replicating all of the gateway functionality we use in a local mock gateway object. It stores test customer profiles in Redis and masks saved billing info in the same way that the real API does. For us, this was a huge win, saving several minutes on each test run.

Why would I want this?

If you use ActiveMerchant and the CIM API, you probably want something like this! It’s fairly feature complete, so apart from speeding up testing, you can hack on your full ecommerce app on a plane, including (dummy) checkout!

Aw yeah! Where do I get it then?

The code is just in a gist for now since we’re not sure if there’s an audience for a nice tidy gem. Also we’re relying on our own tests to test the functionality of the mock, so there are no specific tests included.

Here’s a quick walkthrough of the code. - Mock gateway code implements ActiveMerchant::Billing::AuthorizeNetCimGateway but instead of sending HTTP requests to Auth.net API, it saves customer profiles, payment profiles and transactions in Redis. - Rails initializer: in the test environment, set the mock gateway as a global variable, else set up the real gateway instance. - Test setup: wipe out the mock data in between each test. This is mainly to avoid an O(N) search through all customer profiles looking for matching emails. - Example test snippet

But… I’m scared!

Using the initializer pattern included in the gist, you can always set FORCE_AUTH_NET=true in your environment and run your test suite against the (sandbox I hope!) Authorize.net servers.


Feedback

Welcomed via email (aoneill@h*****.com) or twitter: @werkshy or pull requests on the gist.

License

This code is released under the MIT License.