DOBLES DE PRUEBA CON PHPUNIT: MOCKS, STUBS Y EJEMPLOS

Antes de ponerse a ver que son los dobles de prueba en phpunit creo que hay que leer sobre las pruebas unitarias con phpunit y sobre las aserciones.
Hay funcionalidades que no dependen de otros componentes y se pueden hacer pruebas unitarias sobre esas funcionalidades. Pero hay otras funcionalidades que dependen de otros componentes y probar esas funcionalidades pueden llevar a casos indeseados, como envío de emails o cobros indeseados. Muchos diréis que los sistemas de cobros tienen modo de pruebas y que en un sistema de envío de email se puede cambiar los emails de bbdd o deshabilitar el envío de emails de ese servidor o de la máquina local. En phpunit estas pruebas se llaman dobles de pruebas. Los dobles de prueba con phpunit consiste en crear clases stub y mock. La clase mock contendrá las funcionalidades que queremos evitar que se ejecuten, por ejemplo el envío de emails. Y la clase stub es la clase de pruebas que contiene la clase mock:
En el siguiente ejemplo se puede ver que tenemos una clase user y que se quiere probar que se le manda un email. Esta es la clase stub.

use PHPUnit\Framework\TestCase;

class UserTest extends TestCase
{
    public function testNotificationIsSent()
    {
   $mock = $this->createMock(Mailer::class);
   $mock->method('sendMessage')->willReturn(true);

   $result = $mock->sendMessage('gonzalo@example.com', 'Hola');
   $this->assertTrue($result);
}
En el ejemplo de arriba se crea el objeto mock y el parámetro es "Mailer::class" que es la clase definida abajo. Con el método "$mock->method('sendMessage')" se le indica que método de la calse mailer llamar y con el método "$mock->willReturn(true)" se indica que tiene que devoler y hay realizar los asserts correspondientes.

class Mailer
{

    /**
     * Send a message
     *
     * @param string $email The email address
     * @param string $message The message
     *
     * @return boolean True if sent, false otherwise
     */
    public function sendMessage($email, $message)
    {
   if (empty($email))   {
  throw new Exception;
   }
   
   // Use mail() or PHPMailer for example
   sleep(3);

   echo "send '$message' to '$email'";

   return true;
    }
}