CiviCRM Community Forums (archive)

*

News:

Have a question about CiviCRM?
Get it answered quickly at the new
CiviCRM Stack Exchange Q+A site

This forum was archived on 25 November 2017. Learn more.
How to get involved.
What to do if you think you've found a bug.



  • CiviCRM Community Forums (archive) »
  • Discussion »
  • Extensions (Moderators: mathieu, totten, kasiawaka) »
  • Unit-testing for extensions
Pages: [1]

Author Topic: Unit-testing for extensions  (Read 1447 times)

totten

  • Administrator
  • Ask me questions
  • *****
  • Posts: 695
  • Karma: 64
Unit-testing for extensions
October 09, 2012, 08:34:54 am
I've put some updates in branches/v4.2 and in civix for unit-testing extensions ( http://issues.civicrm.org/jira/browse/CRM-10922 ).

The current approach is basically this:

  • Extension unit-tests follow the same coding conventions as core unit tests. They are based on PHPUnit and should go inside an extension folder named "tests/phpunit". For example, one might create a test file called "tests/phpunit/CRM/Myextension/MyTest.php" with a class name "CRM_Myextension_MyTest".
  • To run an extension unit test on the command-line, one should use "civix test" instead of directly calling "tools/scripts/phpunit"

Code: [Select]
cd $EXTDIR/com.example.myextension
civix test CRM_Myextension_MyTest

  • There is/was a technical hurdle in activating extensions for testing. Our documented setup for CiviCRM unit-testing is to instruct the developer to create a headless test database ('civicrm_tests_dev') and preconfigure the schema with all CiviCRM tables (eg "mysql civicrm_tests_dev < sql/civicrm.mysql"); during the testing process, those tables are frequently truncated. This process has the advantage that the slow/expensive step of creating tables is executed rarely (eg when first installing from SVN or when using setup.sh), but it doesn't work out-of-the-box with extensions. For example, there is no way to manage/install extensions on the headless test database. In fact, the list of active extensions (from table {civicrm_extension}) was frequently truncated.
  • In the current implementation, "civix test" is a wrapper for the normal "tools/scripts/phpunit" -- the wrapper will check the developer's normal CiviCRM instance for a list of active extensions. These extensions are automatically installed and uninstalled on the test database. The installation and uninstallation are performed *once* for each invocation of "civix test". This adds some overhead to running unit-tests. The overhead feels acceptable on on my laptop with one or two extensions, but I don't know if it's acceptable on other machines, and I suspect it will grow untenable if we have a large number of extensions. Some kind of optimization should be implemented.

I think it's reached a "complete enough" point where others can try it out and kick around ideas/issues. If you have any thoughts on unit-testing for extensions -- either general thoughts or specific implementation thoughts -- please let me know.

Eileen

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4195
  • Karma: 218
    • Fuzion
Re: Unit-testing for extensions
October 11, 2012, 12:03:54 am
Tim,

Is it possible to test a hook within a normal unit test? ie. I want to test setting setting defaults by hook & then reverting to them.
Make today the day you step up to support CiviCRM and all the amazing organisations that are using it to improve our world - http://civicrm.org/contribute

totten

  • Administrator
  • Ask me questions
  • *****
  • Posts: 695
  • Karma: 64
Re: Unit-testing for extensions
October 11, 2012, 10:19:32 am
I once wrote a Drupal module (for PHP 5.2) which allowed you to test Drupal hooks using more OO techniques, e.g.

Code: [Select]
<?php
class MyTest extends DrupalTestCase {
  function 
setUp() {
    
ModuleObject::reset();
    
parent::setUp();
  }

  
/**
   * Use SimpleTest's "Mock Object" API. Notice that $mock is an object with
   * methods named "form_alter" and "nodeapi". Once registration is
   * complete, methods are bound to the module's hooks such that:
   *
   *   "function mymodule_form_alter(...)" <==> "$mock->form_alter(...)"
   *   "function mymodule_nodeapi(...)" <==> "$mock->nodeapi(...)"
   */
  
function testB() {
    
Mock::generate('stdClass', 'MockHooksA', array('form_alter', 'nodeapi'));
    
$mock = new MockHooksA();
    
$mock->expectOnce('form_alter');
    
$mock->expectNever('nodeapi');
    
ModuleObject::register('placeholdermodule', $mock);

    ... do 
something that should trigger hook_form_alter but not hook_nodeapi ...
  }

  
/**
   * Use "create_function" to write the hook inline, performing any
   * desired assertions. This is a little more verbose, but it
   * enables you to author detailed tests with the hook's inputs/outputs.
   */
  
function testC() {
    
$adhoc = ModuleObject::adhoc();
    
$adhoc['form_alter'] = create_function('$form, $form_state, $form_id', '
      static $count = 0;
      $count++;

      $test = SimpleTest::getContext()->getTest();
      $test->assertTrue($count <= 1, '
hook_form_alter should be called once');
      //Detailed inspection// $test->assertEqual($form['
foo']['bar'], 'whizbang', 'The foo.bar element is wrong!');
    '
);
    
$adhoc['nodeapi'] = create_function('', '
      $test = SimpleTest::getContext()->getTest();
      $test->fail('
hook_nodeapi should not be called');
    '
);

    ... do 
something that should trigger hook_form_alter but not hook_nodeapi ...
  }

}

There are a bunch of little details that should be different in our situation -- e.g. our tests should run without bootstrapping Drupal; we use phpunit instead of SimpleTest; PHP 5.3 provides nicer syntax for "create_function"; and the internal wiring could revolve around CRM_Utils_Hook_UnitTest. It would probably take me half a day to implement/document a suitable hook-testing mechanism.

totten

  • Administrator
  • Ask me questions
  • *****
  • Posts: 695
  • Karma: 64
Re: Unit-testing for extensions
October 12, 2012, 01:14:07 pm
More instructions are at:

http://wiki.civicrm.org/confluence/display/CRMDOC42/Create+a+Module+Extension#CreateaModuleExtension-Addaunit-testclass

Pages: [1]
  • CiviCRM Community Forums (archive) »
  • Discussion »
  • Extensions (Moderators: mathieu, totten, kasiawaka) »
  • Unit-testing for extensions

This forum was archived on 2017-11-26.