kamilwylegala / cakephp2-php8

CakePHP 2 fork that supports PHP 8
116 stars 51 forks source link

Tests with PHPUnit ^9.5 and PHP 8 #68

Closed nebojsa-dabic closed 3 months ago

nebojsa-dabic commented 3 months ago

If someone can help me, I have problems with PHPUnit testing. Please correct me if I am doing something wrong, but when i try to run Cake tests I found several problems. Let's use command from CakePHP Doc:

Console/cake test app AllTests

Issue 1. First I receive an error from main test dispatcher file /cakephp2-php8/lib/Cake/TestSuite/CakeTestSuiteDispatcher.php method loadTestFramework. Problem is that method try to check does class exist with old PHPUnit namespace in class name with underscores PHPUnit_Framework_TestCase. That is for older versions of PHPUnit (such as 4.*)

line 152 - if (class_exists('PHPUnit_Framework_TestCase')) {...

It is working when i replace old classname with this PHPUnit\Framework\TestCase. That is the problem in multiple files, and on some places PHPUnit classnames are written ok with new namespace. So problem is in that mix where some files use new namespace with class name and some files use old style I needed to replace all old namespaces with new one (approximate 65 times inside 13 files) Here is the list of files:

screen 1

Issue 2. After all replaces, I found that some CakeTest classes extends final PHPUnit classes which cause an error. Than I edited my vendor/phpunit I removed final prefix in these classes:

Class CakeTestLoader cannot extend final class PHPUnit\Runner\StandardTestSuiteLoader in lib/Cake/TestSuite/CakeTestLoader.php Class CakeTestRunner cannot extend final class PHPUnit\TextUI\TestRunner in lib/Cake/TestSuite/CakeTestCase.php

Issue 3. Than I get error for method declaration which is not compatible with extended PHPUnit class methods inside Cake/TestSuite/CakeTestCase.php:

Declaration of CakeTestCase::setUp() must be compatible with PHPUnit\Framework\TestCase::setUp() Declaration of CakeTestCase::tearDown() must be compatible with PHPUnit\Framework\TestCase::tearDown()

Here I also fix PHPUnit\Framework\TestCase instde vendor/phpunit.


After I fix all 3 issues my command for testing is working now Console/cake test app AllTests.

I think that this is not the right way to do because i made changes inside core framework files, and also changes inside vendor/phpunit directory.

Is there another way to run cake tests inside this framework?

Thanks in advanced

kamilwylegala commented 3 months ago

Hey @nebojsa-dabic ! Thanks for creating this issue.

Could you tell me why are you trying to run framework tests? The best source to see how tests are executed is to check GitHub actions configuration, you can see there that tests run with AllTestsTest.

During tests migration not all test files were migrated, likely CakeTestSuiteDispatcher is one of the places that needs fixing. But frankly, I'm not sure if it's worth it.

Regarding removing final from PHPUnit, yep - that's not the way to go. Looks like CakeTestLoader is not used during AllTestsTest.

nebojsa-dabic commented 3 months ago

Thanks for your answer @kamilwylegala

I will than rewrite all my tests to work like AllTestsTest.

kamilwylegala commented 2 months ago

@nebojsa-dabic Is this about writing more tests for the framework or your application?

If it's about the app, I really recommend decoupling from CakePHP test classes. Actually you don't need cake classes at all. Pure PHPUnit + correct bootstrap configuration is enough run tests.

Here is mine cakephp_bootstrap.php (found it somewhere in the Internet, then extended):

<?php

set_time_limit(0);
ini_set('display_errors', 1);
ini_set('memory_limit', "2048M"); //2GB for Psalm.

if (!defined('DS')) {
    define('DS', DIRECTORY_SEPARATOR);
}

if (!defined('ROOT')) {
    define('ROOT', dirname(__FILE__).DS."..");
}

if (!defined('APP_DIR')) {
    define('APP_DIR', 'app');
}

define('CAKE_CORE_INCLUDE_PATH', ROOT.DS.'vendor'.DS.'cakephp'.DS.'cakephp'.DS.'lib');

if (!defined('WEBROOT_DIR')) {
    define('WEBROOT_DIR', basename(dirname(__FILE__)));
}
if (!defined('WWW_ROOT')) {
    define('WWW_ROOT', dirname(__FILE__).DS);
}

if (!defined('CAKE_CORE_INCLUDE_PATH')) {
    if (function_exists('ini_set')) {
        ini_set('include_path', ROOT.DS.'lib'.PATH_SEPARATOR.ini_get('include_path'));
    }
    if (!include('Cake'.DS.'bootstrap.php')) {
        $failed = true;
    }
} else {
    if (!include(CAKE_CORE_INCLUDE_PATH.DS.'Cake'.DS.'bootstrap.php')) {
        $failed = true;
    }
}
if (!empty($failed)) {
    trigger_error(
        "CakePHP core could not be found.  Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php.  It should point to the directory containing your ".DS."cake core directory and your ".DS."vendors root directory.",
        E_USER_ERROR
    );
}

if (Configure::read('debug') < 1) {
    die(__d('cake_dev', 'Debug setting does not allow access to this url.'));
}

require_once __DIR__.DS.'../vendor/autoload.php';

App::uses("ClassRegistry", 'Utility');
App::uses("Security", "Utility");
App::uses("CakeRequest", 'Network');
App::uses("SessionComponent", "Controller/Component");
App::uses("Controller", "Controller");
App::uses("AppController", "Controller");

PHPUnit configuration XML

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" beStrictAboutTestsThatDoNotTestAnything="false"
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
>
    <coverage>
        <include>
            <directory suffix=".php">../app</directory>
            <directory suffix=".php">../src</directory>
        </include>
        <exclude>
            <directory suffix=".php">../app/tmp/cache</directory>
            <directory suffix=".php">../app/webroot</directory>
            <directory suffix=".php">../app/Console</directory>
            <directory suffix=".php">../app/Config</directory>
            <directory suffix=".php">../src/Resources/config</directory>
        </exclude>
    </coverage>
    <extensions>
        <extension class="TestFramework\PHPUnit\TestMetricsExtension"/>
    </extensions>
    <listeners>
        <listener class="JohnKary\PHPUnit\Listener\SpeedTrapListener">
            <arguments>
                <array>
                    <element key="slowThreshold">
                        <integer>500</integer>
                    </element>
                </array>
            </arguments>
        </listener>
    </listeners>
    <php>
        <env name="APP_ENV" value="test" force="true"/>
    </php>
</phpunit>

Then I run tests following way:

./bin/phpunit \
    --color=always \
    --bootstrap tests/bootstrap_phpunit.php \
    --configuration tests/configuration_phpunit.xml $1 $2 tests

Thanks to this you can user newer PHPUnit version, independently from the framework.

nebojsa-dabic commented 2 months ago

Thanks a lot, I appreciate it