I’m running into an issue when writing unit tests with PHPUnit using @dataProvider
in a Laravel app. The error I’m receiving is:
PHP Fatal error: Class ‘Eloquent’ not found in /path/to/project/app/models/ExampleClass.php on line 7
It looks like the constant used in the dataProvider
is causing the fatal.
composer.json:
"psr-4": { "Acme\Models\": "app/models" }
phpunit.xml:
<?xml version="1.0" encoding="UTF-8"?> <phpunit backupGlobals="false" backupStaticAttributes="false" bootstrap="bootstrap/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" syntaxCheck="false" > <testsuites> <testsuite name="Application Test Suite"> <directory>./app/tests/</directory> </testsuite> </testsuites> </phpunit>
The example model:
<?php namespace AcmeModels; use Eloquent; class ExampleClass extends Eloquent { /** * @var bool */ const TRUE = true; }
The example test class:
<?php use AcmeModelsExampleClass; class ExampleClassTest extends TestCase { /** * Example test. * * @param int $value * @return void * @dataProvider testExampleTestDataProvider */ public function testExampleTest($value) { $this->assertTrue($value); } /** * Data provider for testExampleTest. * * @return array */ public function testExampleTestDataProvider() { return array( array(ExampleClass::TRUE), ); } }
Stack trace:
PHP Stack trace: PHP 1. {main}() /usr/local/bin/phpunit:0 PHP 2. PHPUnit_TextUI_Command::main() /usr/local/bin/phpunit:612 PHP 3. PHPUnit_TextUI_Command->run() phar:///usr/local/bin/phpunit/phpunit/TextUI/Command.php:138 PHP 4. PHPUnit_TextUI_Command->handleArguments() phar:///usr/local/bin/phpunit/phpunit/TextUI/Command.php:148 PHP 5. PHPUnit_Util_Configuration->getTestSuiteConfiguration() phar:///usr/local/bin/phpunit/phpunit/TextUI/Command.php:696 PHP 6. PHPUnit_Util_Configuration->getTestSuite() phar:///usr/local/bin/phpunit/phpunit/Util/Configuration.php:837 PHP 7. PHPUnit_Framework_TestSuite->addTestFiles() phar:///usr/local/bin/phpunit/phpunit/Util/Configuration.php:924 PHP 8. PHPUnit_Framework_TestSuite->addTestFile() /path/to/project/vendor/phpunit/phpunit/src/Framework/TestSuite.php:400 PHP 9. PHPUnit_Framework_TestSuite->addTestSuite() /path/to/project/vendor/phpunit/phpunit/src/Framework/TestSuite.php:374 PHP 10. PHPUnit_Framework_TestSuite->__construct() /path/to/project/vendor/phpunit/phpunit/src/Framework/TestSuite.php:289 PHP 11. PHPUnit_Framework_TestSuite->addTestMethod() /path/to/project/vendor/phpunit/phpunit/src/Framework/TestSuite.php:188 PHP 12. PHPUnit_Framework_TestSuite::createTest() /path/to/project/vendor/phpunit/phpunit/src/Framework/TestSuite.php:842 PHP 13. PHPUnit_Util_Test::getProvidedData() /path/to/project/vendor/phpunit/phpunit/src/Framework/TestSuite.php:465 PHP 14. ReflectionMethod->invoke() /path/to/project/vendor/phpunit/phpunit/src/Util/Test.php:392 PHP 15. ExampleClassTest->testExampleTestDataProvider() /path/to/project/vendor/phpunit/phpunit/src/Util/Test.php:392 PHP 16. spl_autoload_call() /path/to/project/vendor/phpunit/phpunit/src/Util/Test.php:27 PHP 17. ComposerAutoloadClassLoader->loadClass() /path/to/project/vendor/phpunit/phpunit/src/Util/Test.php:0 PHP 18. ComposerAutoloadincludeFile() /path/to/project/vendor/composer/ClassLoader.php:278 PHP 19. include() /path/to/project/vendor/composer/ClassLoader.php:386
Advertisement
Answer
I’m having this exact issue. It has to do with the fact that the Laravel aliases (e.g. Config::
, Log::
…) have not been loaded at the time that the @dataProvider
method is called. There are two solutions here that I can think of here.
Solution 1
Modify your @dataProvider
so that it doesn’t use the model class. In my case, I was creating model objects in the @dataProvider method, like this:
public function people() { $person1 = new Person(); $person1->name = "me"; $person2 = new Person(); $person2->name = "you"; return [$person1, $person2]; }
Since the Person
class is referenced in the @dataProvider
method, it’s going to attempt to load that class. Then it will fail because the Eloquent
class alias hasn’t been created by Laravel yet.
To get around this, I could just return the data, and create the actual model objects in the test itself:
public function people() { return ["me", "you"]; } public function testPerson($name) { $person = new Person(); $person->name = $name; // Assertions... }
In your case, that would mean returning [['true']]
, instead of [[ExampleClass::TRUE]]
.
Solution 2
I see no compelling reason to use the Eloquent
class alias here. In fact, I don’t know why it exists at all (except perhaps that it “looks” better?). I brought this up in the IRC channel, and didn’t get a response… So if there’s a reason to use the alias here, then I don’t know it.
That said, if your model class extends the underlying IlluminateDatabaseEloquentModel
class instead of the Eloquent
alias, then your tests will start working as-is.
<?php namespace AcmeModels; use IlluminateDatabaseEloquentModel; class ExampleClass extends Model { /** * @var bool */ const TRUE = true; }