Beim Schreiben von Unit-Tests besteht eine zentrale Herausforderung darin, sicherzustellen, dass sich Ihre Tests auf den zu testenden Code konzentrieren, ohne Störungen durch externe Systeme oder Abhängigkeiten. Hier kommen Mock-Objekte in PHPUnit ins Spiel. Sie ermöglichen es Ihnen, das Verhalten realer Objekte kontrolliert zu simulieren, wodurch Ihre Tests zuverlässiger und einfacher zu warten sind. In diesem Artikel untersuchen wir, was Scheinobjekte sind, warum sie nützlich sind und wie man sie effektiv in PHPUnit verwendet.
Mock-Objekte sind simulierte Versionen realer Objekte, die in Unit-Tests verwendet werden. Sie ermöglichen Ihnen:
Mocks sind besonders nützlich in den folgenden Szenarien:
Bei der Arbeit mit Scheinobjekten werden Sie auf zwei Begriffe stoßen: stubbing und mocking:
PHPUnit erleichtert das Erstellen und Verwenden von Scheinobjekten mit der Methode createMock(). Nachfolgend finden Sie einige Beispiele, die zeigen, wie Sie effektiv mit Scheinobjekten arbeiten.
In diesem Beispiel erstellen wir ein Scheinobjekt für eine Klassenabhängigkeit und geben dessen Verhalten an.
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); } }
Erläuterung:
Manchmal müssen Sie überprüfen, ob eine Methode mit den richtigen Parametern aufgerufen wird. So können Sie das tun:
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(); }
Wichtige Punkte:
Um die reale Anwendung von Scheinobjekten zu demonstrieren, nehmen wir das Beispiel einer PaymentProcessor-Klasse, die von einer externen PaymentGateway-Schnittstelle abhängt. Wir möchten die Methode „processPayment“ von PaymentProcessor testen, ohne uns auf die tatsächliche Implementierung des PaymentGateway zu verlassen.
Hier ist die PaymentProcessor-Klasse:
class PaymentProcessor { private $gateway; public function __construct(PaymentGateway $gateway) { $this->gateway = $gateway; } public function processPayment(float $amount): bool { return $this->gateway->charge($amount); } }
Jetzt können wir ein Modell für das PaymentGateway erstellen, um die Methode „processPayment“ zu testen, ohne mit dem eigentlichen Zahlungsgateway zu interagieren.
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)); } }
Aufschlüsselung des Tests:
Sie können auch überprüfen, ob die Abbuchungsmethode bei der Verarbeitung einer Zahlung genau einmal aufgerufen wird:
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); }
In diesem Beispiel stellt „expected($this->once())“ sicher, dass die Charge-Methode genau einmal aufgerufen wird. Wenn die Methode nicht oder mehr als einmal aufgerufen wird, schlägt der Test fehl.
Angenommen, Sie haben eine UserService-Klasse, die zum Abrufen von Benutzerdaten auf ein UserRepository angewiesen ist. Um UserService isoliert zu testen, können Sie das UserRepository verspotten.
class UserService { private $repository; public function __construct(UserRepository $repository) { $this->repository = $repository; } public function getUserName($id) { $user = $this->repository->find($id); return $user->name; } }
Um diese Klasse zu testen, können wir das Repository verspotten:
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)); } }
Mock-Objekte sind unschätzbare Werkzeuge zum Schreiben von Unit-Tests in PHPUnit. Sie ermöglichen es Ihnen, Ihren Code von externen Abhängigkeiten zu isolieren und so sicherzustellen, dass Ihre Tests schneller, zuverlässiger und einfacher zu warten sind. Scheinobjekte helfen auch dabei, Interaktionen zwischen dem zu testenden Code und seinen Abhängigkeiten zu überprüfen und sicherzustellen, dass sich Ihr Code in verschiedenen Szenarien korrekt verhält
Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.
Copyright© 2022 湘ICP备2022001581号-3