PHPUnit. Test a branch of code that depends on php.ini settings unchanged at runtime

Question:

Background

Some "not_very_good" hosting services like to disable certain functions through php.ini without any alternative. In particular, the sometimes useful parse_ini_file . In my project (lightweight skeleton api) bypassed this way:

if (function_exists('parse_ini_file')) {
    self::$settings = parse_ini_file(PROPERTIES);
    return;
}
$content = preg_grep("/^[\w .]+=.*/", explode(PHP_EOL, file_get_contents(PROPERTIES)));
foreach ($content as $row) {
    $row                    = strstr($row . ';', ';', true);
    $key                    = trim(strstr($row, '=', true), " \n\r");
    $value                  = trim(strstr($row, '=', false), " \"=\n\r");
    self::$settings[ $key ] = $value;
}

Question

How can I now screw PHPUnit to test a piece of code with a handwritten parser?

It would be ideal to designate it at runtime, but somehow I could not find any information about it.

PS Actually, I am at the very beginning of learning PHPUnit and, perhaps, there is a true way, which I simply do not know.

Answer:

Came in from the back door.

Moved the self-written parser into a separate private method

private static function loadSettings() {
    self::$settings = function_exists('parse_ini_file')
        ? parse_ini_file(PROPERTIES)
        : self::loadSettingsHard();
}

private static function loadSettingsHard() {
    $settings = [];
    $content  = preg_grep("/^[\w .]+=.*/", explode("\n", file_get_contents(PROPERTIES)));
    foreach ($content as $row) {
        $row              = strstr($row . ';', ';', true);
        $key              = trim(strstr($row, '=', true), " \n\r");
        $settings[ $key ] = trim(strstr($row, '=', false), " \"=\n\r");
    }

    return $settings;
}

In the test method, I applied a dirty hack with Reflection

public function testGetConfigValueHard() {
    $method = new ReflectionMethod(
        Config::class, 'loadSettingsHard'
    );
    $method->setAccessible(true);
    $method->invoke(Config::class);
    $this->assertEquals(
        'localhost',
        Config::get('db_host')
    );
}

All in all, this task allowed me to look at testing from an unexpected angle. To cover this functionality with tests, I was forced to reduce the cyclomatic complexity of my code (in fact, I applied the principle of single responsibility), which is one of the pillars of a good application architecture.

As for answering the question, you can remove a function at runtime using the runkit_function_remove function, which is included in the runkit PECL extension. For many reasons, this approach is undesirable.

Scroll to Top
AllEscort