Al escribir pruebas unitarias, un desafío clave es garantizar que sus pruebas se centren en el código bajo prueba sin interferencia de sistemas externos o dependencias. Aquí es donde entran en juego los objetos simulados en PHPUnit. Le permiten simular el comportamiento de objetos reales de forma controlada, haciendo que sus pruebas sean más confiables y fáciles de mantener. En este artículo, exploraremos qué son los objetos simulados, por qué son útiles y cómo usarlos de manera efectiva en PHPUnit.
Los objetos simulados son versiones simuladas de objetos reales utilizados en pruebas unitarias. Te permiten:
Los simulacros son particularmente útiles en los siguientes escenarios:
Cuando trabajes con objetos simulados, encontrarás dos términos: stubbing y mocking:
PHPUnit facilita la creación y el uso de objetos simulados con el método createMock(). A continuación se muestran algunos ejemplos que demuestran cómo trabajar eficazmente con objetos simulados.
En este ejemplo, creamos un objeto simulado para una dependencia de clase y especificamos su comportamiento.
use PHPUnit\Framework\TestCase; class MyTest extends TestCase { public function testMockExample() { // Create a mock for the SomeClass dependency $mock = $this->createMock(SomeClass::class); // Specify that when the someMethod method is called, it returns 'mocked value' $mock->method('someMethod') ->willReturn('mocked value'); // Pass the mock object to the class under test $unitUnderTest = new ClassUnderTest($mock); // Perform the action and assert that the result matches the expected value $result = $unitUnderTest->performAction(); $this->assertEquals('expected result', $result); } }
Explicación:
A veces, es necesario verificar que se llama a un método con los parámetros correctos. Así es como puedes hacerlo:
public function testMethodCallVerification() { // Create a mock object $mock = $this->createMock(SomeClass::class); // Expect the someMethod to be called once with 'expected argument' $mock->expects($this->once()) ->method('someMethod') ->with($this->equalTo('expected argument')) ->willReturn('mocked value'); // Pass the mock to the class under test $unitUnderTest = new ClassUnderTest($mock); // Perform an action that calls the mock's method $unitUnderTest->performAction(); }
Puntos clave:
Para demostrar la aplicación en el mundo real de objetos simulados, tomemos el ejemplo de una clase PaymentProcessor que depende de una interfaz PaymentGateway externa. Queremos probar el método de pago del proceso de PaymentProcessor sin depender de la implementación real de PaymentGateway.
Aquí está la clase PaymentProcessor:
class PaymentProcessor { private $gateway; public function __construct(PaymentGateway $gateway) { $this->gateway = $gateway; } public function processPayment(float $amount): bool { return $this->gateway->charge($amount); } }
Ahora podemos crear un simulacro de PaymentGateway para probar el procesoMétodo de pago sin interactuar con la pasarela de pago real.
use PHPUnit\Framework\TestCase; class PaymentProcessorTest extends TestCase { public function testProcessPayment() { // Create a mock object for the PaymentGateway interface $gatewayMock = $this->createMock(PaymentGateway::class); // Define the expected behavior of the mock $gatewayMock->method('charge') ->with(100.0) ->willReturn(true); // Inject the mock into the PaymentProcessor $paymentProcessor = new PaymentProcessor($gatewayMock); // Assert that processPayment returns true $this->assertTrue($paymentProcessor->processPayment(100.0)); } }
Desglose de la prueba:
También puedes verificar que el método de cobro se llame exactamente una vez al procesar un pago:
public function testProcessPaymentCallsCharge() { $gatewayMock = $this->createMock(PaymentGateway::class); // Expect the charge method to be called once with the argument 100.0 $gatewayMock->expects($this->once()) ->method('charge') ->with(100.0) ->willReturn(true); $paymentProcessor = new PaymentProcessor($gatewayMock); $paymentProcessor->processPayment(100.0); }
En este ejemplo, expects($this->once()) garantiza que el método de carga se llame exactamente una vez. Si el método no se llama, o se llama más de una vez, la prueba fallará.
Supongamos que tiene una clase UserService que depende de un UserRepository para recuperar datos del usuario. Para probar UserService de forma aislada, puedes burlarte del UserRepository.
class UserService { private $repository; public function __construct(UserRepository $repository) { $this->repository = $repository; } public function getUserName($id) { $user = $this->repository->find($id); return $user->name; } }
Para probar esta clase, podemos burlarnos del repositorio:
use PHPUnit\Framework\TestCase; class UserServiceTest extends TestCase { public function testGetUserName() { // Create a mock for the UserRepository $mockRepo = $this->createMock(UserRepository::class); // Define that the find method should return a user object with a predefined name $mockRepo->method('find') ->willReturn((object) ['name' => 'John Doe']); // Instantiate the UserService with the mock repository $service = new UserService($mockRepo); // Assert that the getUserName method returns 'John Doe' $this->assertEquals('John Doe', $service->getUserName(1)); } }
Los objetos simulados son herramientas invaluables para escribir pruebas unitarias en PHPUnit. Le permiten aislar su código de dependencias externas, lo que garantiza que sus pruebas sean más rápidas, confiables y fáciles de mantener. Los objetos simulados también ayudan a verificar las interacciones entre el código bajo prueba y sus dependencias, asegurando que su código se comporte correctamente en varios escenarios
Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.
Copyright© 2022 湘ICP备2022001581号-3