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 Folgendes:
Mocks sind in den folgenden Szenarien besonders nützlich:
Wenn Sie mit Scheinobjekten arbeiten, stoßen Sie auf zwei Begriffe: 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); } }
Erklärung:
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:
You can also verify that the charge method is called exactly once when processing a payment:
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 this example, expects($this->once()) ensures that the charge method is called exactly once. If the method is not called, or called more than once, the test will fail.
Let’s assume you have a UserService class that depends on a UserRepository to fetch user data. To test UserService in isolation, you can mock the 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; } }
To test this class, we can mock the repository:
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 objects are invaluable tools for writing unit tests in PHPUnit. They allow you to isolate your code from external dependencies, ensuring that your tests are faster, more reliable, and easier to maintain. Mock objects also help verify interactions between the code under test and its dependencies, ensuring that your code behaves correctly in various scenarios
Das obige ist der detaillierte Inhalt vonScheinobjekte beim PHPUnit-Testen verstehen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!