PHP Mocking Final Class

dg/bypass-finals
phpunit partial mock
mockery stub
testing final classes
laravel mockery tutorial
how to mock system class using mockito
cannot mock/spy class java lang string
cannot mock/spy class java net url

I am attempting to mock a php final class but since it is declared final I keep receiving this error:

PHPUnit_Framework_Exception: Class "Doctrine\ORM\Query" is declared "final" and cannot be mocked.

Is there anyway to get around this final behavior just for my unit tests without introducing any new frameworks?


Since you mentioned you don't want to use any other framework, you are only leaving yourself one option: uopz

uopz is a black magic extension of the runkit-and-scary-stuff genre, intended to help with QA infrastructure.

uopz_flags is a function that can modify the flags of functions, methods and classes.

<?php
final class Test {}

/** ZEND_ACC_CLASS is defined as 0, just looks nicer ... **/

uopz_flags(Test::class, null, ZEND_ACC_CLASS);

$reflector = new ReflectionClass(Test::class);

var_dump($reflector->isFinal());
?>

Will yield

bool(false)

How to Mock Final Classes in PHPUnit, Since you mentioned you don't want to use any other framework, you are only leaving yourself one option: uopz. uopz is a black magic extension of the  Which is the whole point of mocking.And the implementation can - or should, for the more strict developer - be final. Yes, you’ll have twice the amount of files, but it increases the maintainability of your application in my opinion. If the class does nothing more than contain data no interface is needed, but mocking isn’t either.


Late response for someone who is looking for this specific doctrine query mock answer.

You can not mock Doctrine\ORM\Query because its "final" declaration, but if you look into Query class code then you will see that its extending AbstractQuery class and there should not be any problems mocking it.

/** @var \PHPUnit_Framework_MockObject_MockObject|AbstractQuery $queryMock */
$queryMock = $this
    ->getMockBuilder('Doctrine\ORM\AbstractQuery')
    ->disableOriginalConstructor()
    ->setMethods(['getResult'])
    ->getMockForAbstractClass();

PHP Mocking Final Class, In short: you can't mock classes defined as final with PHPUnit. But how can you test a class properly that depends on such a final class, if you  You cannot mock a final class with Mockito, as you can’t do it by yourself. What I do, is to create a non-final class to wrap the final class and use as delegate. An example of this is TwitterFactory class, and this is my mockable class:


I suggest you to take a look at the mockery testing framework that have a workaround for this situation described in the page: Dealing with Final Classes/Methods:

You can create a proxy mock by passing the instantiated object you wish to mock into \Mockery::mock(), i.e. Mockery will then generate a Proxy to the real object and selectively intercept method calls for the purposes of setting and meeting expectations.

As example this permit to do something like this:

class MockFinalClassTest extends \PHPUnit_Framework_TestCase {

    public function testMock()
    {
        $em = \Mockery::mock("Doctrine\ORM\EntityManager");

        $query = new Doctrine\ORM\Query($em);
        $proxy = \Mockery::mock($query);
        $this->assertNotNull($proxy);

        $proxy->setMaxResults(4);
        $this->assertEquals(4, $query->getMaxResults());
    }

I don't know what you need to do but, i hope this help

Mocking final classes in unit tests, Testing final classes is tricky, but possible even though you cannot directly mock a "final" class. FinalClass.php. <?php. namespace FinalClass;. One of the primary restrictions of mock objects in PHP, is that mocking classes or methods marked final is hard. The final keyword prevents methods so marked from being replaced in subclasses (subclassing is how mock objects can inherit the type of the class or object being mocked).


There is a small library Bypass Finals exactly for such purpose. Described in detail by blog post.

Only you have to do is enable this utility before classes are loaded:

DG\BypassFinals::enable();

Testing final classes is tricky, but possible even though you cannot , Tests: 1, Assertions: 1, Warnings: 1. phpunit-mock-objects 5.0. PHPUnit 6.5.1 by Sebastian Bergmann and contributors. PHP Fatal error: Class  Mocking a final class is just as easy as mocking any other class: Similar to the test above, we create a concrete instance and a mock instance of our final class, mock a method and verify that the mocked instance behaves differently. 5.


2019 answer for PHPUnit

I see you're using PHPUnit. You can use bypass finals from this answer.

The setup is just a bit more than bootstrap.php. Read "why" in How to Mock Final Classes in PHPUnit.

Here is "how" ↓

2 Steps

You need to use Hook with bypass call:

<?php declare(strict_types=1);

use DG\BypassFinals;
use PHPUnit\Runner\BeforeTestHook;

final class BypassFinalHook implements BeforeTestHook
{
    public function executeBeforeTest(string $test): void
    {
        BypassFinals::enable();
    }
}

Update phpunit.xml:

<phpunit bootstrap="vendor/autoload.php">
    <extensions>
        <extension class="Hook\BypassFinalHook"/>
    </extensions>
</phpunit>

Then you can mock any final class:

Mocking interface with final return types fails since 6.5.x · Issue #388 , class definition with the final keyword stripped. Pretty wild. I've done some pretty crazy stuff with PHP but had no idea you could natively hack streams like this. PHP 5 introduces the final keyword, which prevents child classes from overriding a method by prefixing the definition with final. If the class itself is being defined final then it cannot be extended.


How to Mock Final Classes in PHPUnit : PHP, BypassFinals requires PHP version 5.6 and supports PHP up to 7.2. It can be used together with any test tool such as PHPUnit or Mockery. This functionality is​  Both Mockito and EasyMock cannot mock classes (or methods) that are final. This article will show you how to mock such classes while continuing to use your favorite mocking framework (Mockito for the sake of this article).


How to Mock Final Classes? » phpFashion, PHP 5 introduces the final keyword, which prevents child classes from like what you say, but my mocking tool doesn't work with final classes". Mocking final methods or classes Quick summary. Use the @RunWith(PowerMockRunner.class) annotation at the class-level of the test case. Use the @PrepareForTest(ClassWithFinal.class) annotation at the class-level of the test case. Use PowerMock.createMock(ClassWithFinal.class) to create a mock object for all methods of this class (let's call it mockObject).


Final classes by default, why?, <?php use PHPUnit\Framework\TestCase; /** * final class that should be a mock in a test */ final class Foo { public function bar() { return 5; } } class FinalTest  Mocking of final classes and methods is an incubating, opt-in feature. It uses a combination of Java agent instrumentation and subclassing in order to enable mockability of these types. It uses a combination of Java agent instrumentation and subclassing in order to enable mockability of these types.