2

I have an abstract class Exception in custom namespace which has no abstract methods. All methods are shown as covered by its tests (mocked in a standard way). The reason to make it abstract is unimportant.

Then I have about 10 classes that extend Exception but don't add or override any methods, properties, constants, etc. It is obvious that all of them should be covered too, but they are shown as not fully covered. I read the docs and googled for a while but didn't find the answer.

  • PHP_CodeCoverage 1.1.3
  • PHPUnit 3.6.12
  • PHP 5.4.4
  • Xdebug 2.2.1-5.4-vc9

While annotating with @codeCoverageIgnore is a solution I want to find out why it happens this way rather then get 100% coverage.

UPD: sources.

------------- abstract class ----------

namespace Jade\Core\Base;


abstract class Exception extends \Exception {
    /**
     * Additional info for exception
     * @var array|null
     */
    protected $info;

    public function __construct($message, array $info = null, $code = 0, \Exception $previous = null) {
        parent::__construct($message, $code, $previous);
        $this->info = $info;
    }

    /**
     * Get the Exception additional info
     * @return mixed
     */
    public function getInfo() {
        return $this->info;
    }
}

------------- Tests for abstract class ----------

class ExceptionTest extends \PHPUnit_Framework_TestCase {
    /**
     * @covers \Jade\Core\Base\Exception
     *
     * @group  public
     */
    public function testGetInfo() {
        $info = array('info' => 'test');
        $stub = $this->getMockForAbstractClass('\Jade\Core\Base\Exception', array('message', $info));

        $this->assertEquals($info, $stub->getInfo());
    }

    /**
     * @covers \Jade\Core\Base\Exception
     *
     * @group  public
     */
    public function testConstructWithDefaultInfo() {
        $stub = $this->getMockForAbstractClass('\Jade\Core\Base\Exception', array('message'));
        $this->assertEmpty($stub->getInfo());
    }
}

------------- class that extends abstract class ----------

namespace Jade\Core\Exceptions;


class Dict extends \Jade\Core\Base\Exception {
}

Code coverage tool output

Update

Renaming \Jade\Core\Base\Exception to avoid possible collision with \Exception didn't help (i tried \Jade\Core\Base\Ixception).

Making Exception class a regular class, not abstract also didn't help.

3
  • Can you post an example of which lines are shown as not covered? Is it the class declaration or the braces? Commented Aug 18, 2012 at 8:41
  • Thanks for edit, i add sources and CodeCoverage output. Commented Aug 18, 2012 at 10:15
  • Yeah, it's my fault. I experimented with the declaration to make it works as expected and forgot to undo changes. I fixed it in question, the problem with coverage is not solved. Commented Aug 19, 2012 at 14:44

2 Answers 2

1

The class declaration is viewed as executable code by Xdebug, and you must use that class ('\Jade\Core\Exceptions\Dict' above) in order to show it as covered. Since this class is designed to be instantiated, you must create at least one object using it.

As posted your tests are not instantiating Dict, and therefore Dict is in fact not covered. You need to change your mock object creation to use Dict instead of \Jade\Core\Base\Exception.

$stub = $this->getMockForAbstractClass('\Jade\Core\Exceptions\Dict', ...);

Note

PHPUnit and PHP_CodeCoverage merely interpret the data supplied by Xdebug which has a few corner cases where non-executable code is treated as executable including close braces on if and else blocks, the class declaration not counted as executed even when you instantiate it, and stating that non-existent lines before and after the file contents are executed. If you can create a minimal test case to demonstrate a true problem, post it to Xdebug's issue tracker.

Sign up to request clarification or add additional context in comments.

6 Comments

\Jade\Core\Exceptions\Dict thrown internally in my \Jade\Core\Base\Dict class. Also i updated my question with note that making \Jade\Core\Base\Exception a regular (non-abstract) class didn't help. Actually, as we can see in example, \Jade\Core\Exceptions\Dict extend \Jade\Core\Base\Exception but didn't add new functionality (methods, props) so i thought it should be also covered based on tests for \Jade\Core\Base\Exception. BTW, when namespaces used we should give full class name, with namespace $stub = $this->getMockForAbstractClass('\Jade\Core\Exceptions\Dict', ...);
I will try to create less complicated example to demonstrate the problem, as you recommended.
@pinepain - The dictionary JCBD throws the exception JCED, but your test creates a mock exception--not a dictionary. I still don't see where your tests call code in the dictionary that will cause the exception to be thrown. Your tests even state that they cover that base exception--not the child. You probably have tests for the dictionary that cover the exception, but I want to clarify that the post above contains no code that covers the child exception.
So, the problem is that JCED is show as not covered. Yes, it is not covered, because it has no extra functional. I thought if it's parent JCBE is covered (with or w/o mocks, it doesn't matter, imho) by it's own tests completly. Maybe i miss some point here?
See my rewrite, but long story short is that you must use a class to have it be covered.
|
1

The problem was entirely in class autoloading. To get work i had to manually include files with classes sources in bootstrap file.

2 Comments

Could you be more specific? Maybe some example? I came across the same issue.
I guess you are on your own now, I barely can remember what problem and solution was, sorry.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.