Using wp_mail during an integration test

I was working on some tests for code that involved wp_mail() just the other day. I couldn’t find any docs on it either, but I took a look at the source of mock-mailer.php, and everything was rather simple.

First, you should understand that WordPress always uses the $phpmailer global to hold an instance of the PHPMailer object that is used by wp_mail(). During the tests, the $phpmailer global is automatically set to be an instance of MockPHPMailer instead.

The MockPHPMailer doesn’t actually send any mail, it just collects information about each message that is “sent”. To retrieve this information, you can call the object’s get_sent() method. To retrieve the object itself, it looks like tests_retrieve_phpmailer_instance() is intended to be used.

So in a simple test where you just want to check that no mail was sent, you’d do this:

    $this->assertEmpty( tests_retrieve_phpmailer_instance()->get_sent() );

Of course, you can also perform more complex checks like this (a real-life example from my own tests):

    $email = tests_retrieve_phpmailer_instance()->get_sent();

    $this->assertEquals( array( array( '[email protected]', '' ) ), $email->to );

    $this->assertStringMatchesFormat( '%sItem 03%s', $email->body );
    $this->assertStringMatchesFormat( '%sA Donor%s', $email->body );
    $this->assertStringMatchesFormat(
        '%s' . get_the_title( $wish_list_id ) . '%s'
        , $email->body
    );

The email object returned by get_sent() has the following properties:

  • to
  • cc
  • bcc
  • header
  • subject
  • body

If you are expecting multiple emails to be sent in a single test, you can retrieve the second one with get_sent( 1 ), the third one with get_sent( 2 ), and so on (they are stored in a 0-indexed array).

If you want to reset the mailer and discard the captured messages in the middle of a test, you can call reset_phpmailer_instance() (as of WordPress 4.6). You’ll also want to do this after each test, by implementing a tearDown() method like this in your testcase class:

public function tearDown() {

    parent::tearDown();

    reset_phpmailer_instance();
}

And finally, if you want to use the original PHPMailer instance in your tests instead of the mock mailer, just try calling unset( $GLOBALS['phpmailer'] ).

Leave a Comment