phpunit: PHPUnit_Framework_TestCase::createConfiguredMock() doesn't mock protected methods

Q A
PHPUnit version 6.0.8
PHP version 7.1.2
Installation Method Composer

Currently, PHPUnit\Framework\TestCase::createConfiguredMock() doesn’t mock protected methods, and judging by the error message it’s not the expected behavior. It’s also unexpected as technically it is possible to mock a protected method if it’s specified during mock initialization.

Consider the following test:

<?php

use PHPUnit\Framework\TestCase;

class SUT
{
    public function foo()
    {
        return $this->bar();
    }

    protected function bar()
    {
        return 'bar';
    }
}

class ConfiguredMockTest extends TestCase
{
    public function testMockProtectedMethodUsingPartialMock()
    {
        $mock = $this->createPartialMock(SUT::class, ['bar']);
        $mock->method('bar')->willReturn('baz');
        $this->assertEquals('baz', $mock->foo());
    }

    public function testMockProtectedMethodUsingConfiguredMock()
    {
        $mock = $this->createConfiguredMock(SUT::class, [
            'bar' => 'baz'
        ]);
        $this->assertEquals('baz', $mock->foo());
    }
}

It produces the following output:

There was 1 warning:

1) ConfiguredMockTest::testMockProtectedMethodUsingConfiguredMock
Trying to configure method "bar" which cannot be configured because it does not exist, has not been specified, is final, or is static

/home/morozov/Projects/phpunit/src/Framework/TestResult.php:701
/home/morozov/Projects/phpunit/src/Framework/TestCase.php:867
/home/morozov/Projects/phpunit/src/Framework/TestSuite.php:739
/home/morozov/Projects/phpunit/src/Framework/TestSuite.php:739
/home/morozov/Projects/phpunit/src/Framework/TestSuite.php:739
/home/morozov/Projects/phpunit/src/TextUI/TestRunner.php:514
/home/morozov/Projects/phpunit/src/TextUI/Command.php:207
/home/morozov/Projects/phpunit/src/TextUI/Command.php:136

However, SUT::bar() exists, was specified, it’s not final or static.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 15 (2 by maintainers)

Most upvoted comments

@morozov

TestCase::createConfiguredMock() creates a full mock. That is, all (!) methods are mocked, and the configured methods will return the specified return values.

How much sense does it make to configure a protected method of a full mock, when all of the public methods are mocked, and none of them actually have a chance to invoke the protected method?

Adjusting TestCase::createConfiguredMock() to mock the specified methods only, instead of all of them, will break existing behaviour.

For reference, see #2596.

I totally agree with every word of @alex-pravdin-sn. It’s very important for the community to be able to use unit testing in as much software as we can. And we kindly request from php-unit to support us.