Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 Acme\Models;

use Eloquent;

class ExampleClass extends Eloquent
{
    /**
     * @var bool
     */
    const TRUE = true;
}

The example test class:

<?php

use Acme\Models\ExampleClass;

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. Composer\Autoload\ClassLoader->loadClass() /path/to/project/vendor/phpunit/phpunit/src/Util/Test.php:0
PHP  18. Composer\Autoload\includeFile() /path/to/project/vendor/composer/ClassLoader.php:278
PHP  19. include() /path/to/project/vendor/composer/ClassLoader.php:386
like image 449
JudRoman Avatar asked Jan 29 '15 15:01

JudRoman


2 Answers

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 \Illuminate\Database\Eloquent\Model class instead of the Eloquent alias, then your tests will start working as-is.

<?php
namespace Acme\Models;

use \Illuminate\Database\Eloquent\Model;

class ExampleClass extends Model
{
    /**
     * @var bool
     */
    const TRUE = true;
}
like image 95
Thomas Kelley Avatar answered Oct 21 '22 08:10

Thomas Kelley


You have to run this in your dataProvider. As Thomas Kelley says this because it gets the dataProvider data before it have run CreateApplication code ether if you using that trait or you create application your self in the setUp method. This can also generate The data provider specified for x is invalid. PHPStorm will only say No tests executed! if a single test is run.

public function fooDataProvider() {
    $this->refreshApplication(); 
    //Code using laravel
}
like image 1
Mikael Svensson Avatar answered Oct 21 '22 07:10

Mikael Svensson