Skip to content

[BUG] Code coverage with proxy class #7683

@walter-developer

Description

@walter-developer

Execute the command and paste the result below.

Command: uname -a && php -v && composer info | grep hyperf && php --ri swoole

/app # uname -a && php -v && composer info | grep hyperf && php --ri swoole
Linux c98b4afa03e0 6.12.54-linuxkit #1 SMP PREEMPT_DYNAMIC Tue Nov  4 21:39:03 UTC 2025 x86_64 Linux
PHP 8.3.14 (cli) (built: Nov 21 2024 08:44:42) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.14, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.14, Copyright (c), by Zend Technologies
    with Xdebug v3.3.2, Copyright (c) 2002-2024, by Derick Rethans
hyperf-extension/auth              3.1.4    The Hyperf Auth package.
hyperf-extension/hashing           3.1.4    The Hyperf Hashing package.
hyperf-extension/jwt               3.1.23.0 The Hyperf JWT package.
hyperf/amqp                        3.1.63   A amqplib for hyperf.
hyperf/cache                       3.1.63   A cache component for hyperf.
hyperf/code-parser                 3.1.63   A code parser component for Hyperf.
hyperf/codec                       3.1.63   A codec component for Hyperf.
hyperf/collection                  3.1.64   Hyperf Collection package which come from illuminate/collections
hyperf/command                     3.1.64   Command for hyperf
hyperf/conditionable               3.1.63   Hyperf Macroable package which come from illuminate/conditionable
hyperf/config                      3.1.63   An independent component that provides configuration container.
hyperf/constants                   3.1.63   A constants component for hyperf.
hyperf/context                     3.1.63   A coroutine/application context library.
hyperf/contract                    3.1.63   The contracts of Hyperf.
hyperf/coordinator                 3.1.63   Hyperf Coordinator
hyperf/coroutine                   3.1.65   Hyperf Coroutine
hyperf/database                    3.1.65   A flexible database library.
hyperf/database-pgsql              3.1.63   A pgsql handler for hyperf/database.
hyperf/db-connection               3.1.63   A hyperf db connection handler for hyperf/database.
hyperf/devtool                     3.1.63   A Devtool for Hyperf.
hyperf/di                          3.1.65   A DI for Hyperf.
hyperf/dispatcher                  3.1.63   A HTTP Server for Hyperf.
hyperf/elasticsearch               3.1.63   Elasticsearch client for hyperf
hyperf/engine                      2.15.0   Coroutine engine provided by swoole.
hyperf/engine-contract             1.14.0   Contract for Coroutine Engine
hyperf/event                       3.1.63   an event manager that implements PSR-14.
hyperf/exception-handler           3.1.63   Exception handler for hyperf
hyperf/framework                   3.1.63   A coroutine framework that focuses on hyperspeed and flexible, specifically use fo...
hyperf/grpc                        3.1.63   A GRPC basic library for Hyperf.
hyperf/grpc-client                 3.1.65   A GRPC Client for Hyperf.
hyperf/grpc-server                 3.1.63   A GRPC Server for Hyperf.
hyperf/guzzle                      3.1.65   Swoole coroutine handler for guzzle
hyperf/http-message                3.1.65   microservice framework base on swoole
hyperf/http-server                 3.1.65   A HTTP Server for Hyperf.
hyperf/logger                      3.1.63   A logger component for hyperf.
hyperf/macroable                   3.1.63   Hyperf Macroable package which come from illuminate/macroable
hyperf/memory                      3.1.63   An independent component that use to operate and manage memory.
hyperf/model-cache                 3.1.63   A model cache component for hyperf.
hyperf/model-listener              3.1.63   A model listener for Hyperf.
hyperf/pipeline                    3.1.63   Hyperf Macroable package which come from illuminate/pipeline
hyperf/pool                        3.1.63   An independent universal connection pool component.
hyperf/process                     3.1.63   A process component for hyperf.
hyperf/redis                       3.1.63   A redis component for hyperf.
hyperf/serializer                  3.1.63   A serializer component for Hyperf.
hyperf/server                      3.1.63   A base server library for Hyperf.
hyperf/stdlib                      3.1.63   A stdlib component for Hyperf.
hyperf/stringable                  3.1.65   Hyperf Stringable package which come from illuminate/support
hyperf/support                     3.1.65   A support component for Hyperf.
hyperf/tappable                    3.1.63   Hyperf Macroable package which come from illuminate/tappable
hyperf/testing                     3.1.63   Testing for hyperf
hyperf/tracer                      3.1.63   A open tracing system implemented for Hyperf or other coroutine framework
hyperf/translation                 3.1.63   An independent translation component, forked by illuminate/translation.
hyperf/validation                  3.1.65   hyperf validation
hyperf/view                        3.1.63   A view library for Hyperf.
hyperf/view-engine                 3.1.65  
hyperf/watcher                     3.1.63   Hot reload watcher for Hyperf

swoole

Swoole => enabled
Author => Swoole Team <[email protected]>
Version => 6.1.4
Built => Dec  8 2025 09:45:42
host byte order => little endian
coroutine => enabled with boost asm context
epoll => enabled
eventfd => enabled
signalfd => enabled
cpu_affinity => enabled
spinlock => enabled
rwlock => enabled
openssl => OpenSSL 3.1.8 11 Feb 2025
dtls => enabled
http2 => enabled
json => enabled
curl-native => enabled
curl-version => 8.14.1
c-ares => 1.27.0
zlib => 1.3.1
brotli => E16781312/D16781312
mutex_timedlock => enabled
pthread_barrier => enabled
coroutine_pgsql => enabled
coroutine_odbc => enabled
coroutine_sqlite => enabled

Directive => Local Value => Master Value
swoole.enable_library => On => On
swoole.enable_fiber_mock => Off => Off
swoole.enable_preemptive_scheduler => Off => Off
swoole.display_errors => On => On
swoole.use_shortname => Off => Off
swoole.unixsock_buffer_size => 8388608 => 8388608

Description:

Code coverage with proxy class not found

Steps To Reproduce:

roblem: Hyperf Controllers Not Appearing in Code Coverage

When running unit tests in Hyperf projects, the tests pass correctly, but controllers are not counted in the code coverage (PHPUnit + PCOV/Xdebug).

Cause of the Problem

Hyperf uses proxy classes to enable:

  • Dependency injection via annotations (#[Inject])
  • AOP features (cache, transactions, etc.)

These proxies are generated in runtime/container/proxy.

During application bootstrap, the following method is executed:

Hyperf\Di\ClassLoader::init();

This method:

  • Scans all classes
  • Generates proxies
  • Overrides the real class in the Composer classMap

As a result:

  • The code executed in tests is the proxy
  • PCOV/PHPUnit counts coverage for the proxy
  • The real controller class is never counted in the coverage

Where Dependency Injection Happens

Dependency injection occurs exclusively in the proxy via the traits:

use Hyperf\Di\Aop\ProxyTrait;
use Hyperf\Di\Aop\PropertyHandlerTrait;

The generated method in the proxy:

$this->__handlePropertyHandler(CLASS);

is responsible for injecting dependencies.

Attempted Alternatives

  1. Forcing the use of the real class via Composer classMap
$composerLoader = Composer::getLoader();
$composerLoader->addClassMap([
    Controller::class => BASE_PATH . '/src/HTTP/Controllers/Controller.php'
]);
Image

Does not work because when the test runs, PCOV is already observing the proxy class that was previously registered by ClassLoader::init().

  1. Creating a separate bootstrap for testing

A second file /test/bootstrap.php was created and the line was commented out:
// Hyperf\Di\ClassLoader::init();

 XDEBUG_MODE=off vendor/bin/co-phpunit  --bootstrap=test/bootstrap-full.php --coverage-html ./runtime/coverage

 XDEBUG_MODE=off vendor/bin/co-phpunit  --bootstrap=test/bootstrap-unit.php --coverage-html ./runtime/coverage
Image

Result:

  • The real controller class is executed
  • Code coverage works correctly

Limitation:

  • Automatic dependency injection no longer works
  • Protected/private properties must be set manually via Reflection or mocks

Proposed Solution

Develop a way to use Hyperf's DI without generating proxy cache, allowing:

  • Execution of the real class
  • Accurate code coverage
  • Unit tests to run without breaking CI/CD

This would allow automatic dependency injection in test environments while ensuring that the real code is counted in coverage.

I hope this comment can help you and future developers turn this pending issue into a feature, or find an alternative solution.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions