29

Starting a project with Zend Framework 1.10 and Doctrine 2 (Beta1). I am using namespaces in my own library code.

When generating code coverage reports I get a Fatal Error about Redeclaring a class. To provide more info, I've commented out the xdebug_disable() call in my phpunit executable so you can see the function trace (disabled local variables output because there was too much output).

Here's my Terminal output:

$ phpunit
PHPUnit 3.4.12 by Sebastian Bergmann.

........

Time: 4 seconds, Memory: 16.50Mb

OK (8 tests, 14 assertions)

Generating code coverage report, this may take a moment.PHP Fatal error:  Cannot redeclare class Cob\Application\Resource\HelperBroker in /Users/Cobby/Sites/project/trunk/code/library/Cob/Application/Resource/HelperBroker.php on line 93
PHP Stack trace:
PHP   1. {main}() /usr/local/zend/bin/phpunit:0
PHP   2. PHPUnit_TextUI_Command::main() /usr/local/zend/bin/phpunit:54
PHP   3. PHPUnit_TextUI_Command->run() /usr/local/zend/share/pear/PHPUnit/TextUI/Command.php:146
PHP   4. PHPUnit_TextUI_TestRunner->doRun() /usr/local/zend/share/pear/PHPUnit/TextUI/Command.php:213
PHP   5. PHPUnit_Util_Report::render() /usr/local/zend/share/pear/PHPUnit/TextUI/TestRunner.php:478
PHP   6. PHPUnit_Framework_TestResult->getCodeCoverageInformation() /usr/local/zend/share/pear/PHPUnit/Util/Report.php:97
PHP   7. PHPUnit_Util_Filter::getFilteredCodeCoverage() /usr/local/zend/share/pear/PHPUnit/Framework/TestResult.php:623

Fatal error: Cannot redeclare class Cob\Application\Resource\HelperBroker in /Users/Cobby/Sites/project/trunk/code/library/Cob/Application/Resource/HelperBroker.php on line 93

Call Stack:
    0.0004     322888   1. {main}() /usr/local/zend/bin/phpunit:0
    0.0816    4114628   2. PHPUnit_TextUI_Command::main() /usr/local/zend/bin/phpunit:54
    0.0817    4114964   3. PHPUnit_TextUI_Command->run() /usr/local/zend/share/pear/PHPUnit/TextUI/Command.php:146
    0.1151    5435528   4. PHPUnit_TextUI_TestRunner->doRun() /usr/local/zend/share/pear/PHPUnit/TextUI/Command.php:213
    4.2931   16690760   5. PHPUnit_Util_Report::render() /usr/local/zend/share/pear/PHPUnit/TextUI/TestRunner.php:478
    4.2931   16691120   6. PHPUnit_Framework_TestResult->getCodeCoverageInformation() /usr/local/zend/share/pear/PHPUnit/Util/Report.php:97
    4.2931   16691148   7. PHPUnit_Util_Filter::getFilteredCodeCoverage() /usr/local/zend/share/pear/PHPUnit/Framework/TestResult.php:623

(I have no idea why it shows the error twice...?)

And here is my phpunit.xml:

<phpunit bootstrap="./code/tests/application/bootstrap.php" colors="true">
    <!-- bootstrap.php changes directory to trunk/code/tests,
    all paths below are relative to this directory. -->

    <testsuite name="My Promotions">
        <directory>./</directory>
    </testsuite>

    <filter>
        <whitelist>
            <directory suffix=".php">../application</directory>
            <directory suffix=".php">../library/Cob</directory>
            <exclude>
                    <!-- By adding the below line I can remove the error -->
                <file>../library/Cob/Application/Resource/HelperBroker.php</file>
                <directory suffix=".phtml">../application</directory>
                <directory suffix=".php">../application/doctrine</directory>
                <file>../application/Bootstrap.php</file>
                <directory suffix=".php">../library/Cob/Tools</directory>
            </exclude>
        </whitelist>
    </filter>

    <logging>
        <log type="junit" target="../../build/reports/tests/report.xml" />
        <log type="coverage-html" target="../../build/reports/coverage" charset="UTF-8"
            yui="true" highlight="true" lowUpperBound="50" highLowerBound="80" />
    </logging>
</phpunit>

I have added a tag inside the which seams to hide this problem. I do have another application resource but it doesn't seam to have a problem (the other one is a Doctrine 2 resource). I'm not sure why it is specific to this class, my entire library is autoloaded so their isn't any include/require calls anywhere. I guess it should be noted that HelperBroker is the first file in the filesystem stemming out from library/Cob

I am on Snow Leopard with the latest/recent versions of all software (Zend Server, Zend Framework, Doctrine 2 Beta1, Phing, PHPUnit, PEAR).

Cobby
  • 291
  • 1
  • 3
  • 3
  • Upon editing pear/PHPUnit/Framework/TestResult.php to dump included files it seams for some reason that the file in question is listed has Helperbroker.php and not HelperBroker.php! (The file is in fact HelperBroker.php) which is why the include_once statement in TestResult.php was still trying to load the file. All other files that are included are correct case. I will now investigate why the file is case-insensitive – Cobby May 12 '10 at 06:09
  • 1
    It seams that the standard naming convention for Zend Framework plugins (which includes Zend_Application resources) is ucfirst() and not camelCase like regular library files. Renaming the file to Helperbroker.php fixes the issue. – Cobby May 12 '10 at 06:34
  • 3
    Write your answer as an answer and accept it, this way the question has a place here and can help others too! – markus Nov 12 '11 at 16:01
  • @alexander-v-ilyin What do you expect from the answer to be applicable for the bounty? Op seems to have solved his problem somewhat but one could write up a general 'how to get rid of that error' answer or something. How are the answers out of date and what is the current issue :) – edorian Nov 22 '11 at 20:53

6 Answers6

35

General answer to wrap this problem up:

This error message usually points to a problem with auto loading and or require statements.

During code coverage report generation phpunit is requireing every *.php that is in <whitelist>. This can be turned off using addUncoveredFilesFromWhitelist=false as a parameter but it is recommended to keep this on.

Possible reasons

What tends to happen in these cases is that one of the files has a require statement that requires an already loaded class again (as it is not a require_once).

Other reasons can be

  • the duplicate definition of classes (one for debugging one for production, should be solved by inheritance not by loading the right php file)

  • Inconsistent capitalization leading to errors in the php code like:

    if( !$classesLoaded['ThIsClass']) require_once(...); in multiple places with different capitalizations.

  • The class not getting loaded at all in the tests but a mock object was created with the name of the then loaded class. Those can collide and lead to that error too

Community
  • 1
  • 1
edorian
  • 38,542
  • 15
  • 125
  • 143
  • 1
    In my case fatal happens at "require_once" place, so I do not really understand why it's possible. – Alexander V. Ilyin Nov 25 '11 at 12:06
  • 1
    @AlexanderV.Ilyin Put a debug_backtrace in the file declaring the class and one in the file requiring it ("again") and see if that helps. Just to get rid of it "quickly" you can exclude the file from the white listing and see if that helps and gets you on the right track. – edorian Nov 25 '11 at 13:03
  • @AlexanderV.Ilyin also take a look @ XDebug - it provides nice stack traces on any PHP error / exceptions. (I do wish XDebug was CLI aware however - scanning HTML tables for stack details in the console gets tiring and 4am) - looks like XDebug does support CLI better than I thought: http://derickrethans.nl/cli-color.html – Bob Gregor Nov 11 '13 at 18:25
  • When using autoloading - ie by using composer - it is sufficient to call for a class with different capitalisation to trigger this error! I stumbled over it because a class called ```WhitespaceTokenizer``` has been called in a test via ```new WhiteSpaceTokenizer```. The result was a completely missing codecoverage for that class. – heiglandreas Jan 08 '14 at 14:28
  • Updating PHPUnit via `composer update` remedied things for me so maybe there are a few things in PHPUnit that deal with file autoloading different between versions. It's probably an obvious thing to try, but just in case anybody else has similar problems. – leggetter May 13 '15 at 13:01
  • The case sensitivity between Windows (not CS) and Cygwin (CS) was the issue. I had to override SPL's auto load to fix it. – Xenos Nov 11 '16 at 16:31
  • This helped me My problem was a mock with same name! The problem was failing to include/require the file containing the type in question where the mock was declared. – Taoist May 24 '17 at 10:05
3

One other thing to check (particularly if you are working with a VM) is whether a file has been renamed but still exists in the original form. eg. fooMapper.php renamed to FooMapper.php (eg. via SVN update), your IDE detects the new file and sends it to the VM. You now have both versions on your VM even if your IDE locally only shows one. Beware.

Jon Gilbert
  • 866
  • 8
  • 5
0

This happened to me because I had a typo in my @covers declaration. Notice the extra \ in the first line.

App\Controller\\Account\UsersController::forgotPassword()

VS

App\Controller\Account\UsersController::forgotPassword()
styks
  • 3,193
  • 1
  • 23
  • 36
0

I had a similar problem, because I used all the files for the coverage instructions. When I set concrete directory and needed files my problem was solved.

I think your problem is here:

<testsuite name="My Promotions">
    <directory>./</directory>
</testsuite>

Here you required all the files and directories.

Try this case to require only tests (or set your folders):

<testsuite name="My Promotions">
    <directory>tests</directory>
</testsuite>

You also can use prefixes, suffixes and files:

0

A quick workaround may be to add an if statement at the beggining of your class declaration in order to avoid redeclaration when running phpunit (if, and only if, that's the only class you're having problems with)

if (!class_exists("class_name")) {
    // declare the class
    class class_name
    {
        //...
    }
}
erickthered
  • 901
  • 8
  • 14
  • 1
    This adds too much complexity "voiding" a bug's consequence instead of understanding and fixing the real bug. – Xenos Nov 11 '16 at 16:32
-1

I found that I received this error when an incorrect @coversDefaultClass (same likely applies to @covers too) annotation was used. In my case it was \Path\To\\Class (with double '\') which was messing with the require calls.

damiankloip
  • 494
  • 4
  • 4