Search code examples
phpphpunitautoload

Autoload file for a simple PHP unit test not working


I am trying to get familiar with PHPUnit, I followed all the instructions here("Getting Started with PHPUnit 7").

I copy/pasted those src/Email.php and tests/EmailTest.php code sources. My problem is when I try to run ./phpunit --bootstrap src/autoload.php tests/EmailTest. The documentation says I must create that src/autoload.php, so I followed the first example mentioned here("Autoloading Classes"):

<?php
// Maybe I do not need this require_once() stuff?
require_once('src/Email.php');
require_once('tests/EmailTest.php');

spl_autoload_register(function ($class_name) {
    include $class_name . '.php';
});

$obj  = new Email('[email protected]');
$obj2 = new EmailTest(); 
?>

but I am getting this error message when I test with the previous command:

PHP Error:  Call to private Email::__construct() from context 'PHPUnit\Util\FileLoader' in /var/www/html/php_project/src/autoload.php on line 9
PHP Stack trace:
PHP   1. {main}() /var/www/html/php_project/vendor/phpunit/phpunit/phpunit:0
PHP   2. PHPUnit\TextUI\Command::main() /var/www/html/php_project/vendor/phpunit/phpunit/phpunit:53
PHP   3. PHPUnit\TextUI\Command->run() /var/www/html/php_project/vendor/phpunit/phpunit/src/TextUI/Command.php:159
PHP   4. PHPUnit\TextUI\Command->handleArguments() /var/www/html/php_project/vendor/phpunit/phpunit/src/TextUI/Command.php:170
PHP   5. PHPUnit\TextUI\Command->handleBootstrap() /var/www/html/php_project/vendor/phpunit/phpunit/src/TextUI/Command.php:896
PHP   6. PHPUnit\Util\FileLoader::checkAndLoad() /var/www/html/php_project/vendor/phpunit/phpunit/src/TextUI/Command.php:1035
PHP   7. PHPUnit\Util\FileLoader::load() /var/www/html/php_project/vendor/phpunit/phpunit/src/Util/FileLoader.php:45
PHP   8. include_once() /var/www/html/php_project/vendor/phpunit/phpunit/src/Util/FileLoader.php:57
PHP Fatal error:  Uncaught Error: Call to private Email::__construct() from context 'PHPUnit\Util\FileLoader' in /var/www/html/php_project/src/autoload.php:9
Stack trace:
#0 /var/www/html/php_project/vendor/phpunit/phpunit/src/Util/FileLoader.php(57): include_once()
#1 /var/www/html/php_project/vendor/phpunit/phpunit/src/Util/FileLoader.php(45): PHPUnit\Util\FileLoader::load('/var/www/html/p...')
#2 /var/www/html/php_project/vendor/phpunit/phpunit/src/TextUI/Command.php(1035): PHPUnit\Util\FileLoader::checkAndLoad('src/autoload.ph...')
#3 /var/www/html/php_project/vendor/phpunit/phpunit/src/TextUI/Command.php(896): PHPUnit\TextUI\Command->handleBootstrap('src/autoload.ph...')
#4 /var/www/html/php_project/vendor/phpunit/phpunit/src/TextUI/Command.php(170): PHPUnit\TextUI\Command->handleArguments(Array)
#5 /var/www/html/php_project/vendor/phpunit/phpunit/src/TextUI/Command.php(159): PHPUnit\TextUI\Command->run(Array, true)
#6 /var/www/html/php_project/vendor/phpunit/phpunit/phpunit(53): PHPUnit\TextUI\Command::main()
#7 {main}
  in /var/www/html/php_project/src/autoload.php on line 9

I used such things long time ago, if you can help me to refresh ...

P.S. Given my setup, I rather run ./vendor/bin/phpunit --bootstrap src/autoload.php tests/EmailTest but that does not make difference with what I have written so far.

EDIT:

Following the below comments, I made the constructor public and run again the test, I got this error message:

PHP Fatal error:  Uncaught PHPUnit\Runner\Exception: Class 'tests/EmailTest' could not be found in 'tests/EmailTest.php'. in /var/www/html/php_project/vendor/phpunit/phpunit/src/Runner/StandardTestSuiteLoader.php:99
Stack trace:
#0 /var/www/html/php_project/vendor/phpunit/phpunit/src/Runner/BaseTestRunner.php(130): PHPUnit\Runner\StandardTestSuiteLoader->load('tests/EmailTest', 'tests/EmailTest...')
#1 /var/www/html/php_project/vendor/phpunit/phpunit/src/Runner/BaseTestRunner.php(78): PHPUnit\Runner\BaseTestRunner->loadSuiteClass('tests/EmailTest', '')
#2 /var/www/html/php_project/vendor/phpunit/phpunit/src/TextUI/Command.php(180): PHPUnit\Runner\BaseTestRunner->getTest('tests/EmailTest', '', Array)
#3 /var/www/html/php_project/vendor/phpunit/phpunit/src/TextUI/Command.php(159): PHPUnit\TextUI\Command->run(Array, true)
#4 /var/www/html/php_project/vendor/phpunit/phpunit/phpunit(53): PHPUnit\TextUI\Command::main()
#5 {main}
  thrown in /var/www/html/php_project/vendor/phpunit/phpunit/src/Runner/StandardTestSuiteLoader.php on line 99

enter image description here


Solution

  • If you used Composer to install PHPUnit in my opinion it is best to also use it for autoloading and not bother with that yourself.

    Allow me to share my (opinionated) setup for PHP projects:

    • Classes in ./src/
    • Test-Case classes in ./tests/

    composer.json (check PSR-4 rather than classmap in a bigger project):

    "autoload": {
        "classmap": [
            "src/"
        ]
    },
    "autoload-dev": {
        "classmap": [
            "tests/"
        ]
    },
    

    phpunit.xml (used to save settings so you don't have to pass it in CLI all the time):

    <?xml version="1.0" encoding="UTF-8"?>
    <phpunit bootstrap="vendor/autoload.php">
        <testsuites>
            <testsuite name="Tests">
                <directory suffix="Test.php">./tests</directory>
            </testsuite>
        </testsuites>
    </phpunit>
    

    Then I can just call ./vendor/bin/phpunit without options and it runs all my tests.


    Using classmap it may be necessary to run composer dump to regenerate autoload files after adding new classes/files.