Skip to content

Mocked methods cannot be called from the original constructor of a partially mocked class #5857

@sbuerk

Description

@sbuerk
Q A
PHPUnit version 11.2.0
PHP version 8.2, 8.3
Installation Method Composer + phpunit repo directly

Summary

A class method is called in the constructor and in other
class methods. Using onlyMethods() to mock that method
does not regonized the calling (count) until now, but at
least subsequential calls could be tested and ensured.

This worked until 11.2.0 of phpunit and was detected in
the TYPO3 nightly pipeline automatically pulling in new
dependency versions, like phpunit.

Note: In manual tests this has been reduced to phpunit
and other dependency ruled out. Can be reproduced within
the phpunit source code directly.

Current behavior

Since 11.2.0 this no longer works and a exception like following
is thrown:

Error: Typed property MockObject_ClassCallingMethodInConstructor_b5ada611::$__phpunit_state
must not be accessed before initialization

How to reproduce

This can be reproduced with a simple class:

<?php declare(strict_types=1);

namespace Vendor\Package;

class ClassCallingMethodInConstructor
{
    public function __construct()
    {
        $this->reset();
    }

    public function reset(): void
    {
    }

    public function second(): void
    {
        $this->reset();
    }
}

and having a test like following:

use Vendor\Package\ClassCallingMethodInConstructor;

public function testOnlyMethodCalledInConstructorWorks(): void
{
  $testClassMock = $this->getMockBuilder(ClassCallingMethodInConstructor::class)
     ->onlyMethods(['reset'])
     ->getMock();

  $testClassMock->expects($this::once())->method('reset');
  $testClassMock->second();
}

Expected behavior

Test passes without error (green), which worked until 11.2.0.

Metadata

Metadata

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions