How can you PHPUnit test a Wordpress function containing check_admin_referer ()?

I just started learning PHPUnit using Wordpress. I have a plugin that receives petition data from change.org. One of the functions of the administrator class checks the parameters from the Wordpress administration area and also calls the check_admin_referer () function as part of this check.

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; } 

This PHPUnit test passes if I comment on check_admin_referer() , but I cannot pass it if not.

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

I tried to set nonce, action and _wp_http_referer manually and through wp_nonce_field() via $_POST in the /bootstrap.php tests and in the test class itself. And I read a little about mock objects / methods, but I don’t quite understand how they can be used in this case.

I probably don't completely understand how it all works, but any help would be greatly appreciated!

+5
source share
1 answer

The problem is that the tests run in command line mode, and, of course, the current user is not authenticated there.

There are several alternatives on how to make it work. One option is to mute either the check_admin_referer() authentication function or its base wp_verify_nonce() authentication function. But this is not the best approach, since the tests have an integration flavor, while stubbing is a more approach for unit tests.

A good solution is to authenticate the user to pass the tests. You can do this relatively easily:

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

I am not sure if $this->plugin_admin->plugin_name will work, as it may be private property. That way you can just pass it as a string with hard code:

 public function testValidateSettings() { $_REQUEST['security'] = wp_create_nonce('whatever your plugin name is'); $this->assertTrue($this->plugin_admin->sc_validate_settings()); } 

It would also be great to clean up after your test, so you should definitely do this in your test case:

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

I don’t think you need to clear the newly created nonce after the tests, because the original WP tests do not clear this either.

That is pretty.


Improvement

If all your tests in the test case require authentication, you can put the creation of nonce in setUp() - this will make the test case more beautiful, since the break code will correspond to the setting:

 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()); } 

Sentence

Install Xdebug and connect to it through your IDE - this will help you go through the code step by step and see what does not work the way you expected. This is better than blindly fighting all these noses, http referees, etc.


Note

WP code is pretty sad. A huge list of functions in the global namespace, the lack of OOP, a complete request processing cycle (for example, unexpected die() ) really disappoints, because it significantly expands the code base and testing.

So get ready for big fights with the code :)

+6
source

All Articles