В процессе PHPUnit-тестирования зачастую приходится иметь дело с кодом, который зависит от встроенных функций PHP, например, phpversion()
. Методика тестирования изложена в настоящей статье.
Рассмотрим в качестве простого примера следующий класс, который проверяет текущую версию PHP и сообщает, удовлетворяет ли она требованиям.
<?php /** * Class to check requirements of the plugin. * * @package sample-plugin */ /** * Class Sample_Requirements */ class Sample_Requirements { /** * Check php version. * * @return bool */ public function is_php_version_required() { if ( version_compare( '5.6', phpversion(), '>' ) ) { $this->php_requirement_message(); return false; } return true; } /** * Show notice with php requirement. */ public function php_requirement_message() { // Some code to show the message. } }
Как протестировать метод is_php_version_required()
? Можно, конечно, написать вспомогательный метод, например:
public function phpversion() { return phpversion(); }
и обращаться к нему: $this->phpversion()
. А в тестах моделировать этот метод. Но выглядит это тяжеловесно.
Есть способ подмены встроенных функций PHP. Предоставляет его библиотека lucatume/function-mocker. Она использует библиотеку antecedent/patchwork, которая и делает основную работу через monkey patch.
В bootstrap.php
файл надо добавить use
и инициализацию FunctionMocker:
use tadFunctionMockerFunctionMocker; // Main bootrstrap code... FunctionMocker::init( [ 'whitelist' => [ realpath( PLUGIN_PATH . '/includes' ), ], 'blacklist' => [ realpath( PLUGIN_PATH ), ], 'redefinable-internals' => [ 'phpversion' ], ] );
Здесь whitelist
— путь к папке, где расположены тестируемые классы плагина. В этой папке patchwork будет подменять функции. blacklist
— путь к корневой папке плагина, здесь замен не будет (кроме папки whitelist
). Это важно, потому что некоторые библиотеки (например, тестовая Mockery
) иначе не работают. redefinable-internals
— перечень функций, которые будут изменены при тестировании.
Теперь результат работы встроенной функции можно подменять «на лету», прямо во время выполнения теста:
<?php /** * Test_Sample_Requirements class file * * @package sample-plugin */ use PHPUnitFrameworkTestCase; use tadFunctionMockerFunctionMocker; /** * Class Test_Sample_Requirements * * @group requirements */ class Test_Sample_Requirements extends TestCase { /** * Test if is_php_version_required(). */ public function test_is_php_version_required() { $subject = new Sample_Requirements(); FunctionMocker::replace( 'phpversion', '5.5' ); $this->assertFalse( $subject->is_php_version_required() ); FunctionMocker::replace( 'phpversion', '5.6' ); $this->assertTrue( $subject->is_php_version_required() ); } }
Кроме того, FunctionMocker
предоставляет много дополнительных возможностей: замену статических методов, «подглядывание» за методами, замену глобальных переменных и методов глобальных объектов ( например, $wpdb->get_row
) и т.д.
Источник: KAGG Design