Skip to content

Testing

Automated tests

You should write unit tests for your payment processors.

The way we bring payment processors under CI is by converting them to use guzzle for http requests (this also makes CURL preferred but optional at the server level). Guzzle has support for using mockHandlers to simulate http requests and responses without actually making them - so once we have set up guzzle testing we can supply an expected response and not rely on an outside service. We can also test the contents of the outgoing test - this gives us quick additional cover. There are several examples of this in core - eg. https://github.com/civicrm/civicrm-core/pull/18350/files#diff-bc4fe6e2e8a92ae3d6254fd13210d41e1da563f4c804bed510f4dbcec45d237c

The steps to convert and set up a test are basically:

  1. create the test shell
  2. switch the code from curl to guzzle
  3. switch to live credentials and comment out the mock handler. Use a breakpoint to capture the response from the provider
  4. re-enable the handler, run again - it should fail because we are comparing 'placeholder' with the actual request now
  5. use the failure from the actual request to put into the getExpectedSinglePaymentRequest() function

1. Create the test shell The initial test shell is pretty boilerplate. The guzzle helper class is available to extensions. The key when trying to capture the response is to comment out the line

$this->createMockHandler([$response]);

2. Switch the code from curl to guzzle Actually pretty straight forward. Some variable for different expectations by the processor - e.g content type of xml used in Authorize.net

At this stage our code looks pretty much like the first of the 2 commits in this PR

3. Capture the response Basically key processor credentials into the test so the request works in a test context, and then grab that string and plug it into the tests - these screenshots are from stepping through the PaypalImpl class in phpstorm

Screen Shot showing code getting response from processor site

Screen Shot showing example response

Alternatively you can call

$this->getResponseBodies();
from your test once it has run through

Screen Shot showing testing code

4. Run the test & capture the requests that went out These will be in the test fail or $this->container in your test class. To view them from $this->container you should cast to a string or use the helper $this->getRequestBodies()[0]

Manual testing

Here are some suggestions of what you might test as part of your user acceptance testing.

Important

Don't forget that you need to search specifically for TEST transactions

i.e. from this page civicrm/contribute/search&reset=1 chose "find test transactions".

Standard Payment processor tests

  1. Can process Successful transaction from

    • Event
    • Contribute Form
    • Individual Contact Record (for on-site processors only)

    Transaction should show as confirmed in CiviCRM and on the payment processor

  2. Can include , . & = ' " in address and name fields without problems. Overlong ZIP code is handled.

  3. Can process a failed transaction from a Contribute form.

    Can fix up details & resubmit for a successful transaction.

    e-mail address is successfully passed through to payment processor and payment processor sends e-mails if configured to do so.

    The invoice ID is processed and maintained in an adequate manner.

  4. Any result references and transaction codes are stored in an adequate manner.

Recurring Payment Processor tests

  1. Process a recurring contribution. Check

    • wording on confirm page is acceptable
    • wording on thankyou pages is acceptable
    • wording on any confirmation e-mails is acceptable
    • the payment processor shows the original transaction is successful
    • the payment processor shows the correct date for the next transaction
    • the payment processor shows the correct total number of transactions and / or the correct final date
  2. Try processing different types of frequencies. Preferably test a monthly contribution on the last day of a month where there isn't a similar day in the following month (e.g. 30 January).

  3. Process a transaction without filling in the total number of transactions (there should be no end date set).

  4. Process a recurring contribution with the total instalments set to 1 (it should be treated as a one-off rather than a recurring transaction). It should not show 'recurring contribution' when you search for it in CiviCRM.

  5. Depending on your processor it may be important to identify the transactions that need to be updated or checked. You may wish to check what it being recorded in the civicrm_contribution_recur table for payment processor id, end date and next transaction date.

Specific Live tests

  1. Successful and unsuccessful REAL transactions work.

  2. Money vests into the bank account.

  3. For recurring transactions wait for the first recurrent transaction to vest.

Cookbooks

Populate Help Text on the Payment Processor Administrator Screen

To populate the blue help icons for the settings fields needed for your payment processor at Administer -> System Settings -> Payment Processors follow the steps below:

  1. Add a template file to your extension with a !#twig {htxt id='$ppTypeName-live-$fieldname'} section for each settings field you are using.

    Example:

    The help text for the user-name field for a payment processor with the name 'AuthNet' would be implemented with code like this:

    twig{htxt id='AuthNet-live-user-name'}{ts}Generate your API Login and Transaction Key by logging in to your Merchant Account and navigating to <strong>Settings &raquo; General Security Settings</strong>.{/ts}</p>{/htxt}

    see core /templates/CRM/Admin/Page/PaymentProcessor.hlp for further examples.

  2. Add that template to the CRM_Admin_Form_PaymentProcessor form using a buildForm hook like so:

    if ($formName === 'CRM_Admin_Form_PaymentProcessor') {
        $templatePath = realpath(dirname(__FILE__) . "/templates");
        CRM_Core_Region::instance('form-buttons')->add(array(
          'template' => "{$templatePath}/{TEMPLATE FILE NAME}.tpl",
        ));
      }