21

In recent versions WP_UnitTestCase has included a $factory property.

For example:

$post = $this->factory->post->create();

Where can I find documentation on this useful feature?

26

As far as I know, there is no documentation for it at present. The official source is here.

I have also written a tutorial on unit testing WordPress plugins, which gives some detail about this feature.

One of the advantages of using WP_UnitTestCase is its factories. These can be accessed through the factory member variable. The factory is an object with properties that are each an instance of one of the classes defined in includes/factory.php. What do they do, you ask? They make it very simple to create users, posts, terms, etc., wherever you need them in your test. So, instead of doing this:

$args = array( /* A bunch of user data you had to make up */ );
wp_insert_user( $args );

You can just do this:

$user_id = $this->factory->user->create();

But wait, it gets even better. What if you need many users (or posts, or whatever)? You can just create them in bulk like this:

$user_ids = $this->factory->user->create_many( 25 );

That will create 25 users that you can use in your test.

The factory has the following properties that you can use:

  • $post
  • $attachment
  • $comment
  • $user
  • $term
  • $category
  • $tag
  • $blog

They may all be used in the same manner as demonstrated in the above example with the $user factory. For example, you can create a post like this:

$this->factory->post->create();

You can also specify particular arguments to use for creating the object. In the above example we created a post, but it wasn't assigned to a particular user (the post_author field will default to 0). Sometimes we may want the post assigned to a user instead. We'd do that like this:

$user_id = $this->factory->user->create();
$post_id = $this->factory->post->create( array( 'post_author' => $user_id ) );

Also, if you need more than just the ID of the object you are creating, you don't need to do this:

$post_id = $this->factory->post->create();
$post = get_post( $post_id );

Instead, use the create_and_get() method:

// $post will be an instance of WP_Post 
$post = $this->factory->post->create_and_get();

In this example, we used the post factory, but the same is true for all of the factories.

I think I'll mention this to the WordPress docs team. Maybe we can get this stuff into the plugin and theme handbooks.

Update (June 20, 2015): You can also create your own custom factories!

Update (September 27, 2016): In WordPress 4.4 the tests were updated to provide a static factory() method for accessing the factories, although the factory property is still provided via a magic getter.

  • Domain is dead, and so is the link to the tutorial. Has it been moved? – Josh Habdas May 16 '17 at 2:58
  • @JoshH It appears to be back up now. You probably hit it while the site was running a backup in the middle of the night (my timezone). – J.D. May 16 '17 at 11:19
  • @JoshH I don't know of any unit testing frameworks that use procedural code for the tests. I really doubt that a procedural testing framework would work nearly as well as an OO one anyway, just because of how it needs to work. However, just because the tests are built on an object-oriented framework like PHPUnit doesn't dictate that they can only test OO code. I have lots of procedural code my plugins, and test it in exactly the same way. WordPress also tests lots of procedural code this way. So it should be no problem. – J.D. May 17 '17 at 11:29
  • Thanks @J.D. I'd ideally like to write my tests in this manner too. But I'll submit to OOP given it's not in the main codeline. P.S. I tried submitting a comment on your blog and received an error. squinty face Regardless, thanks for the 411. – Josh Habdas May 17 '17 at 11:33
  • 1
    @JoshH Thanks for the heads up about the issue with comments, this should be fixed now. It was caused by an overzealous anti-spam plugin. – J.D. May 17 '17 at 12:16
2

The source code at

https://github.com/rnagle/wordpress-unit-tests/blob/master/includes/factory.php

seems to be the best place to look at the moment

  • 2
    Just remove the link from your question: What would you read than? Please always write answers that don´t rely on outside sources. Else we´ll need to delete your answer. – kaiser Mar 25 '14 at 12:55
  • 2
    @kaiser, I see where you're coming from, but the answer to my question will be a link. Surely you wouldn't expect someone to post the entire documentation here? – djb Mar 25 '14 at 14:27
  • 2
    Yes, we would expect someone to post all relevant code here. This is even written into the site FAQ-- "Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offline." That may not be the entire content of the linked resource but in this case it may be. As is, when that GitHub resource becomes inaccessible, this answer becomes meaningless. – s_ha_dum Mar 25 '14 at 16:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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