Mockery para PHP: guía completa con ejemplos prácticos
1. ¿Qué es Mockery y para qué sirve?
Mockery es una librería potente y flexible para crear objetos simulados (mock objects) en PHP. Está diseñada para pruebas unitarias (unit testing) y permite a los desarrolladores aislar el código que están probando de sus dependencias. En lugar de usar objetos reales (como conexiones a bases de datos, clientes API o el sistema de archivos), creas "simulaciones" (mocks) que imitan el comportamiento de los originales. Esto hace que las pruebas sean rápidas, confiables e independientes de factores externos.
¿Para qué sirve? Imagina que estás probando la clase OrderProcessor, que envía un email después de procesar un pedido. Si usas un Mailer real, tu prueba será lenta, dependerá de que el servidor SMTP funcione y podría enviar correos a usuarios reales por accidente. Con Mockery creas un Mailer "falso" que simplemente verifica si el método send() fue llamado con los argumentos correctos. Esto te permite concentrarte en la lógica de OrderProcessor, no en la infraestructura.
Mockery no es solo un reemplazo de objetos. Ofrece una API rica para describir expectativas: puedes especificar cuántas veces debe llamarse un método, con qué argumentos, en qué orden y qué debe devolver. Esto hace que las pruebas no solo estén aisladas, sino que también sean autodocumentadas, ya que las expectativas describen explícitamente la interacción entre objetos.
2. Instalación
Mockery se instala a través de Composer, el gestor de paquetes estándar de PHP. Se recomienda instalarla como dependencia de desarrollo (require-dev), ya que no es necesaria en el entorno de producción.
composer require --dev mockery/mockery
Después de la instalación, verifica que tu archivo composer.json contenga la siguiente entrada en la sección require-dev:
{
"require-dev": {
"mockery/mockery": "^1.6"
}
}
Si usas PHPUnit, Mockery se integra con él "de fábrica" mediante el trait \Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration.
3. Inicio rápido
Vamos a crear una prueba simple que demuestre la funcionalidad básica de Mockery. Supongamos que tenemos una clase Calculator que depende de un servicio Logger.
<?php
// Clases de ejemplo
interface Logger {
public function log(string $message): void;
}
class Calculator {
private Logger $logger;
public function __construct(Logger $logger) {
$this->logger = $logger;
}
public function add(int $a, int $b): int {
$result = $a + $b;
$this->logger->log("Sumando $a y $b, resultado: $result");
return $result;
}
}
// Prueba con Mockery
use PHPUnit\Framework\TestCase;
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
class CalculatorTest extends TestCase {
use MockeryPHPUnitIntegration;
public function testAddLogsCorrectly(): void {
// 1. Creamos un mock para Logger
$loggerMock = Mockery::mock(Logger::class);
// 2. Describimos la expectativa: el método log() debe llamarse 1 vez
// con un mensaje específico
$loggerMock->shouldReceive('log')
->once()
->with('Sumando 2 y 3, resultado: 5');
// 3. Creamos el objeto a probar con el mock
$calculator = new Calculator($loggerMock);
// 4.