単体テストを作成するときの重要な課題は、外部システムや依存関係からの干渉なしに、テスト対象のコードに焦点を当てたテストを行うことです。ここで、PHPUnit で モック オブジェクト が登場します。これにより、実際のオブジェクトの動作を制御された方法でシミュレートできるため、テストの信頼性が高まり、保守が容易になります。この記事では、モック オブジェクトとは何か、モック オブジェクトが役立つ理由、PHPUnit でモック オブジェクトを効果的に使用する方法について説明します。
モック オブジェクトは、単体テストで使用される実際のオブジェクトのシミュレートされたバージョンです。これらにより次のことが可能になります:
モックは、次のシナリオで特に役立ちます:
モック オブジェクトを扱うときは、スタブ と モッキング という 2 つの用語に遭遇します。
PHPUnit を使用すると、createMock() メソッドを使用してモック オブジェクトを簡単に作成および使用できます。以下は、モック オブジェクトを効果的に操作する方法を示すいくつかの例です。
この例では、クラスの依存関係のモック オブジェクトを作成し、その動作を指定します。
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); } }
説明:
場合によっては、メソッドが正しいパラメーターで呼び出されているかどうかを確認する必要があります。その方法は次のとおりです:
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(); }
キーポイント:
モック オブジェクトの実際のアプリケーションを示すために、外部の PaymentGateway インターフェイスに依存する PaymentProcessor クラスの例を見てみましょう。 PaymentGateway の実際の実装に依存せずに、PaymentProcessor の processPayment メソッドをテストしたいと考えています。
PaymentProcessor クラスは次のとおりです:
class PaymentProcessor { private $gateway; public function __construct(PaymentGateway $gateway) { $this->gateway = $gateway; } public function processPayment(float $amount): bool { return $this->gateway->charge($amount); } }
これで、PaymentGateway のモックを作成して、実際の支払いゲートウェイと対話せずに processPayment メソッドをテストできるようになりました。
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)); } }
テストの内訳:
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
以上がPHPUnit テストにおけるモック オブジェクトを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。