Skip to content

Commit

Permalink
CiviUnitTestCase - Extract Civi\Test\Api3TestTrait
Browse files Browse the repository at this point in the history
This makes `CiviUnitTestCase` more readable, and it allows other tests to
benefit from these helpers (even if they don't use everything from
`CiviUnitTestCase`).
  • Loading branch information
totten committed Mar 23, 2018
1 parent 933ef83 commit 9542a8c
Show file tree
Hide file tree
Showing 2 changed files with 264 additions and 244 deletions.
262 changes: 262 additions & 0 deletions Civi/Test/Api3TestTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
<?php

namespace Civi\Test;

/**
* Class Api3TestTrait
* @package Civi\Test
*
* This trait defines a number of helper functions for testing APIv3. Commonly
* used helpers include `callAPISuccess()`, `callAPIFailure()`,
* `assertAPISuccess()`, and `assertAPIFailure()`.
*
* This trait is intended for use with PHPUnit-based test cases.
*/
trait Api3TestTrait {

/**
* Api version - easier to override than just a define
*/
protected $_apiversion = 3;

/**
* Check that api returned 'is_error' => 1
* else provide full message
* @param array $result
* @param $expected
* @param array $valuesToExclude
* @param string $prefix
* Extra test to add to message.
*/
public function assertAPIArrayComparison($result, $expected, $valuesToExclude = array(), $prefix = '') {
$valuesToExclude = array_merge($valuesToExclude, array('debug', 'xdebug', 'sequential'));
foreach ($valuesToExclude as $value) {
if (isset($result[$value])) {
unset($result[$value]);
}
if (isset($expected[$value])) {
unset($expected[$value]);
}
}
$this->assertEquals($result, $expected, "api result array comparison failed " . $prefix . print_r($result, TRUE) . ' was compared to ' . print_r($expected, TRUE));
}

/**
* Check that a deleted item has been deleted.
*
* @param $entity
* @param $id
*/
public function assertAPIDeleted($entity, $id) {
$this->callAPISuccess($entity, 'getcount', array('id' => $id), 0);
}

/**
* Check that api returned 'is_error' => 1.
*
* @param array $apiResult
* Api result.
* @param string $prefix
* Extra test to add to message.
* @param null $expectedError
*/
public function assertAPIFailure($apiResult, $prefix = '', $expectedError = NULL) {
if (!empty($prefix)) {
$prefix .= ': ';
}
if ($expectedError && !empty($apiResult['is_error'])) {
$this->assertEquals($expectedError, $apiResult['error_message'], 'api error message not as expected' . $prefix);
}
$this->assertEquals(1, $apiResult['is_error'], "api call should have failed but it succeeded " . $prefix . (print_r($apiResult, TRUE)));
$this->assertNotEmpty($apiResult['error_message']);
}

/**
* Check that api returned 'is_error' => 0.
*
* @param array $apiResult
* Api result.
* @param string $prefix
* Extra test to add to message.
*/
public function assertAPISuccess($apiResult, $prefix = '') {
if (!empty($prefix)) {
$prefix .= ': ';
}
$errorMessage = empty($apiResult['error_message']) ? '' : " " . $apiResult['error_message'];

if (!empty($apiResult['debug_information'])) {
$errorMessage .= "\n " . print_r($apiResult['debug_information'], TRUE);
}
if (!empty($apiResult['trace'])) {
$errorMessage .= "\n" . print_r($apiResult['trace'], TRUE);
}
$this->assertEquals(0, $apiResult['is_error'], $prefix . $errorMessage);
}

/**
* This function exists to wrap api functions.
* so we can ensure they fail where expected & throw exceptions without litterering the test with checks
* @param string $entity
* @param string $action
* @param array $params
* @param string $expectedErrorMessage
* Error.
* @param null $extraOutput
* @return array|int
*/
public function callAPIFailure($entity, $action, $params, $expectedErrorMessage = NULL, $extraOutput = NULL) {
if (is_array($params)) {
$params += array(
'version' => $this->_apiversion,
);
}
$result = $this->civicrm_api($entity, $action, $params);
$this->assertAPIFailure($result, "We expected a failure for $entity $action but got a success", $expectedErrorMessage);
return $result;
}

/**
* wrap api functions.
* so we can ensure they succeed & throw exceptions without litterering the test with checks
*
* @param string $entity
* @param string $action
* @param array $params
* @param mixed $checkAgainst
* Optional value to check result against, implemented for getvalue,.
* getcount, getsingle. Note that for getvalue the type is checked rather than the value
* for getsingle the array is compared against an array passed in - the id is not compared (for
* better or worse )
*
* @return array|int
*/
public function callAPISuccess($entity, $action, $params, $checkAgainst = NULL) {
$params = array_merge(array(
'version' => $this->_apiversion,
'debug' => 1,
),
$params
);
switch (strtolower($action)) {
case 'getvalue':
return $this->callAPISuccessGetValue($entity, $params, $checkAgainst);

case 'getsingle':
return $this->callAPISuccessGetSingle($entity, $params, $checkAgainst);

case 'getcount':
return $this->callAPISuccessGetCount($entity, $params, $checkAgainst);
}
$result = $this->civicrm_api($entity, $action, $params);
$this->assertAPISuccess($result, "Failure in api call for $entity $action");
return $result;
}

/**
* This function exists to wrap api getValue function & check the result
* so we can ensure they succeed & throw exceptions without litterering the test with checks
* There is a type check in this
* @param string $entity
* @param array $params
* @param null $count
* @throws Exception
* @return array|int
*/
public function callAPISuccessGetCount($entity, $params, $count = NULL) {
$params += array(
'version' => $this->_apiversion,
'debug' => 1,
);
$result = $this->civicrm_api($entity, 'getcount', $params);
if (!is_int($result) || !empty($result['is_error']) || isset($result['values'])) {
throw new Exception('Invalid getcount result : ' . print_r($result, TRUE) . " type :" . gettype($result));
}
if (is_int($count)) {
$this->assertEquals($count, $result, "incorrect count returned from $entity getcount");
}
return $result;
}

/**
* This function exists to wrap api getsingle function & check the result
* so we can ensure they succeed & throw exceptions without litterering the test with checks
*
* @param string $entity
* @param array $params
* @param array $checkAgainst
* Array to compare result against.
* - boolean
* - integer
* - double
* - string
* - array
* - object
*
* @throws Exception
* @return array|int
*/
public function callAPISuccessGetSingle($entity, $params, $checkAgainst = NULL) {
$params += array(
'version' => $this->_apiversion,
);
$result = $this->civicrm_api($entity, 'getsingle', $params);
if (!is_array($result) || !empty($result['is_error']) || isset($result['values'])) {
throw new Exception('Invalid getsingle result' . print_r($result, TRUE));
}
if ($checkAgainst) {
// @todo - have gone with the fn that unsets id? should we check id?
$this->checkArrayEquals($result, $checkAgainst);
}
return $result;
}

/**
* This function exists to wrap api getValue function & check the result
* so we can ensure they succeed & throw exceptions without litterering the test with checks
* There is a type check in this
*
* @param string $entity
* @param array $params
* @param string $type
* Per http://php.net/manual/en/function.gettype.php possible types.
* - boolean
* - integer
* - double
* - string
* - array
* - object
*
* @return array|int
*/
public function callAPISuccessGetValue($entity, $params, $type = NULL) {
$params += array(
'version' => $this->_apiversion,
'debug' => 1,
);
$result = $this->civicrm_api($entity, 'getvalue', $params);
if ($type) {
if ($type == 'integer') {
// api seems to return integers as strings
$this->assertTrue(is_numeric($result), "expected a numeric value but got " . print_r($result, 1));
}
else {
$this->assertType($type, $result, "returned result should have been of type $type but was ");
}
}
return $result;
}

/**
* A stub for the API interface. This can be overriden by subclasses to change how the API is called.
*
* @param $entity
* @param $action
* @param array $params
* @return array|int
*/
public function civicrm_api($entity, $action, $params) {
return civicrm_api($entity, $action, $params);
}

}
Loading

0 comments on commit 9542a8c

Please sign in to comment.