activemerchant / active_merchant

Active Merchant is a simple payment abstraction library extracted from Shopify. The aim of the project is to feel natural to Ruby users and to abstract as many parts as possible away from the user to offer a consistent interface across all supported gateways.
http://activemerchant.org
MIT License
4.53k stars 2.5k forks source link

Refactor Gateway#test? method to consider instance-level test mode #408

Closed Soleone closed 11 years ago

Soleone commented 12 years ago

Problem

This is in response to the following fix that had to be put in for the Worldpay gateway: https://github.com/Shopify/active_merchant/pull/405

It is not obvious for a gateway implementor without a lot of ActiveMerchant experience when a gateway is supposed to be in test mode. In the base gateway class we define test mode as only being true if Base.mode is set to :test, i.e. if all of the gateways are put into test mode.

This does not take into consideration that for pretty much all of the gateways you can set test mode on an instance level, e.g. in Shopify we allow each merchant to set their currently selected gateway to test mode temporarily while all other gateways still use production mode.

TODO

I feel like the Gateway class should redefine the test? method to also look at the @options hash that was passed in when initializing the gateway. Currently most concrete gateway implementations overwrite test? do exactly that and it should be a sensible default.

If we just define test? to look at both @options[:test] || Base.gateway_mode == :test then all subclasses don't need to redefine that method anymore in the same way and new gateway implementors have one less mistake to make.

ehutzelman commented 12 years ago

I ran into this issue with the "dual" test modes while trying to setup authorize.net CIM gateway.

The gateway initialize method accepts an options hash with the :test parameter and is documented that it will use the test_url if :test => true. However, the test_url is only actually used when you set the Base.gateway_mode = :test. As far as I can tell, the :test setting in the initializer options hash only turns on an additional XML tag xml.tag!('extraOptions', "x_test_request=TRUE") if @options[:test]. All other test-related decisions are based on the separate Base.gateway_mode setting.

@Soleone proposed fix to use both @options[:test] || Base.gateway_mode to define test? should eliminate a lot of this confusion.

codeodor commented 11 years ago

@ehutzelman, I look at that as a feature: for instance, I want to run a test against the production URL in AuthorizeNet, where you can do that by sending "test" = true.

@ntalbott Did this commit take away our ability to run in test mode on the production URL? And if so, is there an official workaround or will I need to monkey patch it in my tests?

Thanks!

ehutzelman commented 11 years ago

@codeodor If you want to force test mode on production, I believe you can still do that by turning on test mode through the AuthorizeNet web console. However, I'm not sure why you would want to run your tests through production as AuthorizeNet provides a test server specifically for this purpose.

codeodor commented 11 years ago

Thanks @ehutzelman. For the time being I temporarily set test_url = live_url, and switch them back after the test that needs it.

A couple of reasons I've seen where someone wants to test against a production account in test mode:

1) credentials do not have a typo 2) settings on the account in production match the expected settings

Regards, Sam

dbwinger commented 10 years ago

Not sure this is the place to ask this, but I'm really confused about how to run against the sandbox url but not in test mode. Can anyone help me out?