Skip to content
Advertisement

PHPUnit: “Class ‘Eloquent’ not found” when using @dataProvider

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;
}
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement