2

I have written a plugin, and am going through the process of setting up some unit tests for it.

Inside of my unit tests I am utilizing the WP_UnitTest_Factory class to help with the process of creating posts, users etc.

$this->factory->post->create( array( 'post_type' => 'announcement' ) );

I am finding that when I run my unit tests on Travis CI, any reference to WP_UnitTest_Factory on versions outside of LATEST fails.

The error being thrown on Travis CI is:

Notice: Trying to get property of non-object in /home/travis/build/build_name/project/tests/test-helper-functions.php on line 12

This is occuring on 4.1, 4.0, 3.9.2 - but not when WP_Version=latest.

Which is referencing the WP_UnitTest_Factory code (above) to create a post.

My thoughts are that the WP_UnitTest_Factory is included in trunk, so when running on LATEST, the class is available.

When running on older versions, the factory class is not present - thus throwing errors.

I did a bit of research and checked out other plugins unit tests, and they seem to avoid using the factory class altogether, and use built in wp functions (wp_insert_post()).

Is there any way to work around this issue, or should I re-write my tests to use built in WP functions instead of the WP_UnitTest_Factory class, so that my tests will pass on older versions of WordPress?

3

1 Answer 1

3

The problem is not that the factory class is unavailable, because if that were so you would be getting a fatal "class not found" error. The problem is that you aren't using your test case properly. This code (and similar) is what is causing the problem:

/**
 * Testing that timeline_express_get_announcement_date() returns what we expect
 */
public function test_timeline_express_get_announcement_date() {
    // Re-instantiate this class
    $helper_functions_test_class = new TE_Helper_Tests;
    // Create some test announcements, passing in some defaults.
    $announcement_id = $helper_functions_test_class->test_create_announcement( '#FF6347', 'fa-plus', '04/04/1989' );
    // Grab the announcement date
    $announcement_date = timeline_express_get_announcement_date( $announcement_id );
    $comparison_date = date_i18n( get_option( 'date_format' ), strtotime( '04/04/1989' ) );
    // $announcement_date = get_post_meta( $announcement_id, 'announcement_date', true );
    $this->assertEquals( $announcement_date, $comparison_date );
}

Here you are constructing a test case yourself, which means that you are skipping all of the set up that PHPUnit usually performs, like calling the test case's setUp() method (which is where the factory property is set up.

So when you call test_create_acnnouncement() on the class you just constructed, the factory property hasn't been set up, and that's why you are getting these errors.

Instead, you should refactor that test (and others like it) to be something like this:

/**
 * Testing that timeline_express_get_announcement_date() returns what we expect
 */
public function test_timeline_express_get_announcement_date() {
    // Create some test announcements, passing in some defaults.
    $announcement_id = $this->test_create_announcement( '#FF6347', 'fa-plus', '04/04/1989' );
    // Grab the announcement date
    $announcement_date = timeline_express_get_announcement_date( $announcement_id );
    $comparison_date = date_i18n( get_option( 'date_format' ), strtotime( '04/04/1989' ) );
    // $announcement_date = get_post_meta( $announcement_id, 'announcement_date', true );
    $this->assertEquals( $announcement_date, $comparison_date );
}

In other words, just skip the part where you create a new instance of the class, and just use the instance that you already have: $this.

So, why doesn't this error show up when running against the latest version of the test suite? Because the latest version includes a __get() method to provide the factory. So the property doesn't have to be set up in the latest version of the tests. But don't think that this is an indicator that you should be manually constructing the testcases as you were doing, that's not a normal thing.

So to answer your final question, as to whether you should be using the factories or not, the reason that most plugins you've seen were using the built-in WordPress functions may just be because they are ignorant of the factories. While you do not have to use the factories, the benefit of them is that you don't have to make up fake post content, etc., the factory just automatically generates that for you.

1
  • Amazing answer. Makes complete sense now that you have pointed it out. Still getting my feet wet with unit testing, so any piece of knowledge I can gain is invaluable. Greatly appreciate the very detailed response and the help in understanding what's going on at a granular level. Thanks JD!
    – EHerman
    Mar 22, 2016 at 16:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.