Как бы вы PHPUnit протестировали функцию Wordpress, содержащую check_admin_referer()?

Я только начал изучать PHPUnit с Wordpress. У меня есть плагин, который получает данные петиции с сайта change.org. Одна из функций класса администратора проверяет настройки из области администрирования Wordpress, а также вызывает `check_admin_referer() как часть этой проверки.

  public function sc_validate_settings() {
    //check nonce field is valid
    check_admin_referer($this->plugin_name, 'security');    

    //get new settings 
    $settings = $this->sc_clean_new_settings();

    //validate url
    $valid_url = $this->sc_validate_url($settings['petition_url']);

    //validate api_key
    $valid_api_key = $this->sc_validate_api_key($settings['petition_api_key']);

    if ($valid_url && $valid_api_key) {

      $this->clean_settings = $settings;
      return true;

    }

    return false;

  }

Этот тест PHPUnit проходит, если я закомментирую check_admin_referer(), но я не могу заставить его пройти, если нет.

  public function testValidateSettings() {    

    $this->assertTrue($this->plugin_admin->sc_validate_settings());

  }  

Я пытался установить одноразовый номер, действие и _wp_http_referer вручную и через wp_nonce_field() через $_POST в тестах/bootstrap.php и в самом тестовом классе. И я немного читал о фиктивных объектах/методах, но не совсем понимаю, как их можно использовать в этом случае.

Я, вероятно, совершенно неправильно понимаю, как все это работает, но любая помощь будет принята с благодарностью!


person Ed Patrick    schedule 12.08.2016    source источник


Ответы (1)


Проблема в том, что тесты запускаются в режиме командной строки, и, конечно же, текущий пользователь там не аутентифицируется.

Есть несколько вариантов, как заставить его работать. Один из вариантов — заглушить либо функцию проверки авторизации check_admin_referer(), либо лежащую в ее основе функцию wp_verify_nonce(). Но это не лучший подход, так как тесты там носят интеграционный характер, а заглушка больше подходит для юнит-тестов.

Хорошим решением является аутентификация пользователя для прохождения тестов. Вы можете сделать это относительно легко, как это:

public function testValidateSettings() {
    $_REQUEST['security'] = wp_create_nonce($this->plugin_admin->plugin_name);

    $this->assertTrue($this->plugin_admin->sc_validate_settings());
}

Я не уверен, что $this->plugin_admin->plugin_name сработает, так как это может быть частная собственность. Таким образом, вы можете просто передать его как жестко закодированную строку:

public function testValidateSettings() {
    $_REQUEST['security'] = wp_create_nonce('whatever your plugin name is');

    $this->assertTrue($this->plugin_admin->sc_validate_settings());
}

Также было бы здорово провести очистку после вашего теста, поэтому вы обязательно должны иметь это в своем тестовом примере:

public function tearDown() {
    unset($_REQUEST['security']);
}

Я не думаю, что вам нужно очищать вновь созданный одноразовый номер после тестов, потому что оригинальные тесты WP не очищают и его.

Это красиво.


Улучшение

Если все ваши тесты в тестовом примере требуют аутентификации, вы можете поместить nonce-creation в setUp() — это сделает тестовый пример красивее, так как код удаления будет соответствовать коду установки:

public function setUp() {
    $_REQUEST['security'] = wp_create_nonce('whatever your plugin name is');
}

public function tearDown() {
    unset($_REQUEST['security']);
}

public function testValidateSettings() {
    $this->assertTrue($this->plugin_admin->sc_validate_settings());
}

Предложение

Установите Xdebug и подключитесь к нему через IDE — это поможет вам шаг за шагом просмотреть код и увидеть, что работает не так, как вы ожидали. Это лучше, чем слепо бороться со всеми этими нонсами, http-реферерами и т.д.


Примечание

Код WP довольно печальный. Огромный список функций в глобальном пространстве имён, отсутствие ООП, отсутствие полного цикла обработки запросов (например, неожиданный die()) — это реально расстраивает, потому что сильно усложняет расширение кодовой базы и тестирование.

Так что будьте готовы к новым битвам с кодом :)

person Andrey Tserkus    schedule 12.08.2016
comment
Привет @andrey-tserkus, спасибо, что нашли время, чтобы предоставить подробный ответ и контекст. Это сработало! Мне нужно было передать имя плагина в виде жестко закодированной строки, как вы предложили. Хороший совет, чтобы включить в setUp() тоже для красоты! Еще раз спасибо - буду готовиться к будущим боям с WP кодом! - person Ed Patrick; 15.08.2016
comment
Спасибо, @AndreyTserkus. Этот ответ помог мне больше всего. Я не мог заставить аспект $_REQUEST работать, но обнаружил, что если я назначу текущего пользователя, wp_verify_nonce будет работать. Написал короткий пост, который может помочь другим тестировать WordPress. wp_verify_nonce и PHPUnit - person jer0dh; 18.02.2017