3

I'm working on some tests for WordPress, and I discovered that WordPress' PHPUnit automatically captures and doesn't send emails (using MockPHPMailer) when I try to use wp_mail.

I've looked, but I can't seem to find any information on MockPHPMailer. I'd love to know either how to use it or disable it (since before this discovery I'd planned to use Mailtrap). Does anyone know where I might find some information about MockPHPMailer?

  • wp_mail is a pluggable function then you can replace it – mmm Oct 5 '16 at 21:57
  • What would be an example of replacing it with the original PHPMailer? – Pete Oct 5 '16 at 23:30
6

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( 'test@example.com', '' ) ), $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'] ).

  • Is it possible to mock the failure of sending an email? I've looked at the core tests, and I copy/pasted the test in my integration test but it failed (you must provide at least one recipient email address). develop.svn.wordpress.org/trunk/tests/phpunit/tests/mail.php I have a method that is hooked on wp_mail_failed and would like to test it... – dingo_d Sep 24 '18 at 7:56

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.