【问题标题】:How would you PHPUnit test a Wordpress function containing check_admin_referer()?您将如何 PHPUnit 测试包含 check_admin_referer() 的 Wordpress 函数?
【发布时间】:2016-12-19 17:18:49
【问题描述】:

我刚刚开始使用 Wordpress 学习 PHPUnit。我有一个从 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;

  }

如果我注释掉 check_admin_referer(),则此 PHPUnit 测试通过,但如果不注释,则无法通过。

  public function testValidateSettings() {    

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

  }  

我尝试在 tests/bootstrap.php 和测试类本身中手动设置随机数、操作和 _wp_http_referer,并通过 wp_nonce_field()$_POST 设置。而且我已经阅读了一些关于模拟对象/方法的内容,但不太了解它们在这种情况下如何使用。

我可能完全误解了这一切的工作原理,但我们将不胜感激!

【问题讨论】:

    标签: php wordpress phpunit


    【解决方案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']);
    }
    

    我认为您不需要在测试后清理新创建的 nonce,因为 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 连接到它 - 这将帮助您逐步完成代码,看看哪些地方没有按预期工作。这比盲目地与所有那些 nonce、http 引用等作斗争要好。


    注意

    WP 代码非常可悲。全局命名空间中的大量函数列表、缺乏 OOP、没有完整的请求处理周期(例如意外的die())——真的很令人沮丧,因为它使代码库的扩展和测试变得非常困难。

    所以准备好与代码进行更多的战斗:)

    【讨论】:

    • 嗨@andrey-tserkus,感谢您抽出宝贵时间提供详细的答案和上下文。有效!我需要按照您的建议将插件名称作为硬编码字符串传递。为了漂亮,也包含在 setUp() 中的好技巧!再次感谢 - 我会用 WP 代码为未来的战斗做准备!
    • 谢谢,@AndreyTserkus。这个答案对我也很有帮助。我无法让 $_REQUEST 方面工作,但发现如果我设置当前用户,wp_verify_nonce 就可以工作。写了一篇可能有助于其他人测试 WordPress 的短文。 wp_verify_nonce and PHPUnit
    猜你喜欢
    • 2017-09-21
    • 2013-08-02
    • 1970-01-01
    • 2016-09-21
    • 2012-10-19
    • 2015-08-21
    • 2015-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多