Answers.Body: <p>Civi's autoloader does not load classes outside the CRM directory. In order for that to work, you'll have a few options:</p>
  
  <ul>
  <li>Implement your own autoloader capable of loading classes inside the test/phpunit dir</li>
  <li>Use require to include the class</li>
  <li>Put the VolunteerTestAbstract class inside your CRM dir</li>
  </ul>
  
  <p>I usually use the second option for that and include/require the class(es) on the bootstrap.php file. </p>
  
  <p>I also like the third option. For that, you would put the class somewhere like CRM_Volunteer_Test_VolunteerTestAbstract and then just extend it. No need for requires or to implement your own autoloader. </p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-11-12T02:29:49.373Z
Answers.Text: Thanks, Davi. Have called it a day but will have another look over the weekend.
Answers.UserDisplayName: universalhandle
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-11-12T00:32:27.677Z
Answers.LastActivityDate: 2016-11-12T01:26:47.390Z
Answers.LastEditDate: 2016-11-12T01:26:47.390Z
Answers.UserDisplayName: Davi Alexandre
Answers.Body: <p>This is an issue with intermediate base-classes for tests (like <code>VolunteerTestAbstract</code>). The most reliable solution I've found is to put a <code>require_once</code> to load the intermediate base-class. For example, this is what I used in <a href="https://github.com/veda-consulting/uk.co.vedaconsulting.mosaico/blob/e52e7f4753888c8df4a9d27810219fb2700b1279/tests/phpunit/CRM/Mosaico/MosaicoTemplateTest.php" rel="nofollow noreferrer"><code>uk.co.vedaconsulting.mosaico</code></a>:</p>
  
  <pre><code>require_once __DIR__ . '/TestCase.php';
  
  class CRM_Mosaico_MosaicoTemplateTest extends CRM_Mosaico_TestCase implements EndToEndInterface {
       ...
  }
  </code></pre>
  
  <p>Unfortunately, it's hard to combine PHPUnit with a classloader that understands extensions. To see why, consider an example command:</p>
  
  <pre><code>phpunit4 tests/phpunit/CRM/Mosaico/MosaicoTemplateTest.php
  </code></pre>
  
  <p>Which would then:</p>
  
  <ul>
  <li>A. Load test files, e.g.
  
  <ol>
  <li>Load <code>tests/phpunit/bootstrap.php</code></li>
  <li>Load <code>tests/phpunit/CRM/Mosaico/MosaicoTemplateTest.php</code> (which depends on a base class like <code>CRM_Mosaico_TestCase</code>)</li>
  <li>Load <code>tests/phpunit/CRM/Mosaico/TestCase.php</code></li>
  </ol></li>
  <li>B. Begin executing the test logic, e.g.
  
  <ol>
  <li>Execute <code>CiviTestListener</code></li>
  <li>Execute <code>setupBeforeClass()</code></li>
  <li>Execute <code>setUp()</code></li>
  </ol></li>
  </ul>
  
  <p>The problem arises if the database-initialization (eg <code>\Civi\Test::headless()-&gt;installMe(__DIR__)-&gt;apply()</code>) is put in phase B test-logic (e.g. <code>CiviTestListener</code> or <code>setupBeforeClass()</code> or <code>setUp()</code>) . The database-initialization determines which extensions are active. The active extensions determine the class-loader. But all of this comes too late. During steps A2=>A3 (when we need autoloading), the extension-enabled class-loader isn't available yet.</p>
  
  <p>Put another way: any code which references an autoloaded extension class has an implicit dependency on the database.</p>
  
  <p>One can resolve this conundrum a couple ways, e.g.</p>
  
  <ul>
  <li>In <code>tests/phpunit/bootstrap.php</code>, fully initialize the system. (Ex: In the line <code>eval(cv('php:boot --level=classloader', 'phpcode'));</code>, change the <code>--level</code> to <code>settings</code> or <code>full</code>.) This makes sense if all the tests are end-to-end (<code>e2e</code>).</li>
  <li>Load classes in a way which does not implicitly depend on the database. The simplest thing is to do a <code>require_once</code> to load the target class. (EDIT: What's a nice place to put the <code>require_once</code> statement? I originally put it in each test class, but on second thought... it would be more elegant to put it in <code>tests/phpunit/boostrap.php</code>.)</li>
  </ul>
  
  <p>(I'm writing this to help me get the problem a bit clearer in mind... hopefully that will eventually lead to a better solution...)</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-12-28T04:27:22.247Z
Answers.LastActivityDate: 2017-05-23T18:08:21.013Z
Answers.LastEditDate: 2017-05-23T18:08:21.013Z
Answers.UserDisplayName: Tim Otten
Body: <p>I'm following <a href="https://github.com/totten/civix/blob/master/UPGRADE.md#upgrade-test-files" rel="nofollow noreferrer">civix's upgrade instructions</a> to enable unit tests to be executed with standalone phpunit.</p>
  
  <p>I've got my code in a <a href="https://github.com/civicrm/org.civicrm.volunteer/pull/415/commits" rel="nofollow noreferrer">work-in-progress git branch</a>. The first commit captures the civix-generated boilerplate phpunit.xml.dist and bootstrap.php. The second commit captures my attempts to adapt an existing test to the new way of doing things.</p>
  
  <p>With these changes in place, I do:</p>
  
  <pre><code>$ cd /path/to/webroot/sites/all/modules/civicrm/tools/extensions/civivolunteer
  $ phpunit4 tests/phpunit/api/v3/VolunteerProjectTest.php
  </code></pre>
  
  <p>... and get:</p>
  
  <pre><code>PHP Fatal error:  Class 'VolunteerTestAbstract' not found in /path/to/webroot/sites/all/modules/civicrm/tools/extensions/civivolunteer/tests/phpunit/api/v3/VolunteerProjectTest.php on line 6
  PHP Stack trace:
  PHP   1. {main}() /usr/local/lib/civicrm-buildkit/bin/phpunit4:0
  PHP   2. PHPUnit_TextUI_Command::main() /usr/local/lib/civicrm-buildkit/bin/phpunit4:545
  PHP   3. PHPUnit_TextUI_Command-&gt;run() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/TextUI/Command.php:100
  PHP   4. PHPUnit_Runner_BaseTestRunner-&gt;getTest() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/TextUI/Command.php:123
  PHP   5. PHPUnit_Runner_BaseTestRunner-&gt;loadSuiteClass() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/Runner/BaseTestRunner.php:67
  PHP   6. PHPUnit_Runner_StandardTestSuiteLoader-&gt;load() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/Runner/BaseTestRunner.php:123
  PHP   7. PHPUnit_Util_Fileloader::checkAndLoad() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/Runner/StandardTestSuiteLoader.php:39
  PHP   8. PHPUnit_Util_Fileloader::load() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/Util/Fileloader.php:38
  PHP   9. include_once() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/Util/Fileloader.php:56
  </code></pre>
  
  <p>Any suggestions?</p>
  
Tags: <civix><unit-testing><phpunit><autoloading>
Title: Does class autoloading not work in standalone phpunit testing?
ThreadText: # Does class autoloading not work in standalone phpunit testing?
  
  (Asked by: username_0 on 2016-11-11)
  
  I'm following civix's upgrade instructions to enable unit tests to be executed with standalone phpunit.
  I've got my code in a work-in-progress git branch. The first commit captures the civix-generated boilerplate phpunit.xml.dist and bootstrap.php. The second commit captures my attempts to adapt an existing test to the new way of doing things.
  With these changes in place, I do:
  $ cd /path/to/webroot/sites/all/modules/civicrm/tools/extensions/civivolunteer
  $ phpunit4 tests/phpunit/api/v3/VolunteerProjectTest.php
  
  ... and get:
  PHP Fatal error:  Class 'VolunteerTestAbstract' not found in /path/to/webroot/sites/all/modules/civicrm/tools/extensions/civivolunteer/tests/phpunit/api/v3/VolunteerProjectTest.php on line 6
  PHP Stack trace:
  PHP   1. {main}() /usr/local/lib/civicrm-buildkit/bin/phpunit4:0
  PHP   2. PHPUnit_TextUI_Command::main() /usr/local/lib/civicrm-buildkit/bin/phpunit4:545
  PHP   3. PHPUnit_TextUI_Command->run() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/TextUI/Command.php:100
  PHP   4. PHPUnit_Runner_BaseTestRunner->getTest() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/TextUI/Command.php:123
  PHP   5. PHPUnit_Runner_BaseTestRunner->loadSuiteClass() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/Runner/BaseTestRunner.php:67
  PHP   6. PHPUnit_Runner_StandardTestSuiteLoader->load() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/Runner/BaseTestRunner.php:123
  PHP   7. PHPUnit_Util_Fileloader::checkAndLoad() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/Runner/StandardTestSuiteLoader.php:39
  PHP   8. PHPUnit_Util_Fileloader::load() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/Util/Fileloader.php:38
  PHP   9. include_once() phar:///usr/local/lib/civicrm-buildkit/bin/phpunit4/phpunit/Util/Fileloader.php:56
  
  Any suggestions?
  
  **Tags:** civix, unit-testing, phpunit, autoloading
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_1 on 2016-11-12. Score: 2 | Accepted answer
  
  Civi's autoloader does not load classes outside the CRM directory. In order for that to work, you'll have a few options:
  
  * Implement your own autoloader capable of loading classes inside the test/phpunit dir
  * Use require to include the class
  * Put the VolunteerTestAbstract class inside your CRM dir
  
  I usually use the second option for that and include/require the class(es) on the bootstrap.php file.
  
  I also like the third option. For that, you would put the class somewhere like CRM\_Volunteer\_Test\_VolunteerTestAbstract and then just extend it. No need for requires or to implement your own autoloader.
  
  > **Comments:**
  > **username_0**: Thanks, Davi. Have called it a day but will have another look over the weekend.  
  
  ---
  
  ### Answer by username_2 on 2016-12-28. Score: 4
  
  This is an issue with intermediate base-classes for tests (like VolunteerTestAbstract). The most reliable solution I've found is to put a require_once to load the intermediate base-class. For example, this is what I used in uk.co.vedaconsulting.mosaico:
  require_once __DIR__ . '/TestCase.php';
  
  class CRM_Mosaico_MosaicoTemplateTest extends CRM_Mosaico_TestCase implements EndToEndInterface {
       ...
  }
  
  Unfortunately, it's hard to combine PHPUnit with a classloader that understands extensions. To see why, consider an example command:
  phpunit4 tests/phpunit/CRM/Mosaico/MosaicoTemplateTest.php
  
  Which would then:
  
  A. Load test files, e.g.
  
  
  Load tests/phpunit/bootstrap.php
  Load tests/phpunit/CRM/Mosaico/MosaicoTemplateTest.php (which depends on a base class like CRM_Mosaico_TestCase)
  Load tests/phpunit/CRM/Mosaico/TestCase.php
  
  B. Begin executing the test logic, e.g.
  
  
  Execute CiviTestListener
  Execute setupBeforeClass()
  Execute setUp()
  
  
  The problem arises if the database-initialization (eg \Civi\Test::headless()->installMe(__DIR__)->apply()) is put in phase B test-logic (e.g. CiviTestListener or setupBeforeClass() or setUp()) . The database-initialization determines which extensions are active. The active extensions determine the class-loader. But all of this comes too late. During steps A2=>A3 (when we need autoloading), the extension-enabled class-loader isn't available yet.
  Put another way: any code which references an autoloaded extension class has an implicit dependency on the database.
  One can resolve this conundrum a couple ways, e.g.
  
  In tests/phpunit/bootstrap.php, fully initialize the system. (Ex: In the line eval(cv('php:boot --level=classloader', 'phpcode'));, change the --level to settings or full.) This makes sense if all the tests are end-to-end (e2e).
  Load classes in a way which does not implicitly depend on the database. The simplest thing is to do a require_once to load the target class. (EDIT: What's a nice place to put the require_once statement? I originally put it in each test class, but on second thought... it would be more elegant to put it in tests/phpunit/boostrap.php.)
  
  (I'm writing this to help me get the problem a bit clearer in mind... hopefully that will eventually lead to a better solution...)
  
  
  ---
  
  