Skip to content

Instantly share code, notes, and snippets.

@johnregan3
Last active December 21, 2015 07:18
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save johnregan3/6269967 to your computer and use it in GitHub Desktop.
Save johnregan3/6269967 to your computer and use it in GitHub Desktop.
Unit Test for WordPress' save_post{$post_type}
<?php
/**
* This has been tested using the diff for save_post_{$post_type}
* https://core.trac.wordpress.org/changeset/25050
*
* @todo Try different post type names
* @todo Create two posts and try to update them both at the same time
*/
class Save_Post_Post_Type {
/**
* Loads our control data into the test post.
*
* First, we'll save the post using wp_update_post and without save_post_{$post_type}
* We'll use this as a control to compare our $result against later.
* We can't just compare the raw post input with the save_post_{$post_type} because saving
* the post strips slashes, validates, etc.
*
* @param int $test_post_id ID of the post we are testing with.
* @return string $control_result content of post saved with wp_update_post
*/
function control_test( $test_post_id ) {
$control_post = array();
$control_post['ID'] = $test_post_id;
$control_post['post_type'] = 'book';
$control_post['post_content'] = "Initial Data.";
$control_post_id = wp_update_post( $control_post );
/**
* when we save it, it returns a post ID,
* so we'll need to get our content back out of the control post.
*/
$control_post = get_post( $control_post_id);
$control_result = $control_post->post_content;
return $control_result;
}
/**
* Test to see if save_post_{$post_type} hooks into the saving action correctly.
*
* @param int $test_post_id ID of the post we are testing with.
* @param string $input Input from provider() method.
* @return string $test_result Content of post(s) updated with save_post_{$post_type}
*/
function test_save_post_post_type( $test_post_id, $input ) {
//Run the hook that should exist, and attempt to change the data.
add_action( 'save_post_book', $this->modify_content( $test_post_id, $input ) );
//Get post content by id
$result_post = get_post( $test_post_id );
$test_result = $result_post->post_content;
return $test_result;
}
/**
* Save our post with new post_content, on 'save_post_book'
*
* @param int $test_post_id ID of the post we are testing with.
* @param string $input Input from provider() method.
* @return void
*/
function modify_content( $test_post_id, $input ) {
/**
* Attempt to overwrite 'the auto-generated post_content' with $input
* This will be done on 'save_post_book' in test_save_post_type()
*/
$test_post_new_content = array();
$test_post_new_content ['ID'] = $test_post_id;
$test_post_new_content['post_content'] = $input;
wp_update_post( $test_post_new_content );
}
}
/**
* Set Up Test
*/
class Tests_Save_Post_Post_Type extends WP_UnitTestCase {
/**
* Establish testing variables
*
* This information will be passed as the parameter ($input) into our test method in this class.
* Note that we use @dataProvider to let test_save_post_post_type know we're using this method
* Note also that it returns a multidimentional array (an array within an array).
* These values will be passed one at a time into our testing function
*
* @return array Array of input content to test "save_post_{$post_type}"
*/
public function provider() {
return array(
array( '023983775900' ),
array( '(*&@#)*)&*#@*~_)*?(#' ),
array( 'http://wordpress.org' ),
array( 'It\'s a trap!' ),
array( 'These aren\'t the droids you are looking for.' ),
array( 'I find you lack of faith disturbing.' ),
array( 'Ready are you? What know you of ready?' ),
);
}
/**
* Tests to ensure save_post_{$post_type} hooks into save_post correctly.
*
* If these $input and $result don't match, the test will throw an error.
* They should match, displaying that the input matches the output ($result),
* when saved by "save_post_{post_type}".
*
* This function must begin with "test".
*
* @param string $input Input from provider()
* @return bool Pass/Fail test Results
*
* The following line is required to let the test know what method is sending the $input
* @dataProvider provider
*/
public function test_run_test( $input ) {
$test = new Save_Post_Post_Type;
//Create Post using extended class WP_UnitTestCase
$test_post_id = $this->factory->post->create();
$control_result = $test->control_test( $test_post_id );
/**
* Run the test. Send the input, return the result.
*
* This method changes the content of our post into a Star Wars quote.
* If it does not change, it will thow an error. Remember, our original content was,
* "Initial Data."
*/
$test_result = $test->test_save_post_post_type( $test_post_id, $input );
/**
* Compare $control_result content with $test_result content.
*
* Since we attempted to modify the content of the "Book" post, this method "assertFlase"
* checks to see that these two statements do not match.
* There are many other methods you can use here:
* http://phpunit.de/manual/current/en/appendixes.assertions.html
*/
$this->assertNotEquals( $control_result, $test_result);
}
}
@westonruter
Copy link

Could the test not be made way simpler just with something like this?

<?php
/* ... */
function test_update() (
    /* ... */
    $test_post_id = $this->factory->post->create( array( 'post_type' => 'book' ) );
    $called = false;
    $handler = function () use (&$called) {
        $called = true;
    };
    add_action( 'save_post_book', $handler );
    wp_update_post( array( 'ID' => $test_post_id, 'post_title' => 'updated' ) );
    remove_action( 'save_post_book', $handler );
    $this->assertTrue( $called );

@johnregan3
Copy link
Author

@westonruter Wow. I took your advice and cut this code down to about 1/4 the size before I saw your solution. I've noticed that I have quite the penchant for doing things the long way. Nice work!

BTW, that anonymous function is pretty slick. http://bit.ly/171mbtr

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment