zeus / mock
This library allows you to create mock objects.
Requires
- ext-pdo: *
Requires (Dev)
- phpunit/phpunit: ^12.0
README
The MockFactory
class allows for the dynamic creation of mock objects for classes or interfaces, which can be useful in unit testing or when you want to simulate the behavior of an object. This is achieved through method mocking, where you can override methods to return predefined results for testing purposes.
Features
- Mock any class or interface: Create mock objects for both classes and interfaces dynamically.
- Method mocking: Override methods with custom behaviors, defined via closures.
- Supports class inheritance: The mock objects will inherit from the original class, allowing you to test behavior as if the real object was used.
- Supports interface implementation: If the target is an interface, it will generate a mock implementing the interface.
- Flexible mock behavior: Customize method returns and behaviors for specific testing scenarios.
Installation
composer require zeus/mock
Example Usage
use Zeus\Mock\MockFactory; $mockFactory = new MockFactory(); // Create a mock instance of a class $mockObject = $mockFactory->createMock(SomeClass::class); // Mock a specific method on the class $mockFactory->mockMethod('someMethod', fn($arg) => 'mocked result'); // Use the mock object echo $mockObject->someMethod('test'); // Outputs 'mocked result'
Mocking an Interface
interface Logger { public function log(string $message): void; } $mockFactory = new MockFactory(); // Create a mock instance of an interface $mockLogger = $mockFactory->createMock(Logger::class); // Mock the log method $mockFactory->mockMethod('log', fn($message) =>print 'mocked log: ' . $message); // Use the mock interface echo $mockLogger->log('Test'); // Outputs 'mocked log: Test'
Mocking a Service Class with Dependencies
class DatabaseService { private Logger $logger; public function __construct(Logger $logger) { $this->logger = $logger; } public function saveData(string $data): void { // Simulate saving data and logging the action $this->logger->log('Data saved: ' . $data); } } $mockFactory = new MockFactory(); // Mock the Logger interface $mockLogger = $mockFactory->createMock(Logger::class); // Mock the saveData method $mockFactory->mockMethod('log', fn($message) =>print 'mocked log: ' . $message); // Create the mock DatabaseService with the mocked Logger $mockDatabaseService = $mockFactory->createMock(DatabaseService::class,[ 'logger' => $mockLogger ]); // Use the service with mocked behavior $mockDatabaseService->saveData('Test Data'); // Will output 'mocked log: Data saved: Test Data'
Type Hinting and instanceof Check
The MockFactory ensures that type hinting is respected in the mock classes. For example, if a method expects a specific type, the mock will follow that expectation.
class SomeService { public function processData(array $data): int { return count($data); } } $mockFactory = new MockFactory(); // Create a mock instance of SomeService $mockService = $mockFactory->createMock(SomeService::class); // Mock the processData method $mockFactory->mockMethod('processData', fn($data) => 42); // Use the mock object echo $mockService->processData([1, 2, 3]); // Outputs '42' // Check the instance type if ($mockService instanceof SomeService) { echo "It's an instance of SomeService!"; }
Benefits of Type Hinting in Mocks
Avoid type-related issues: Ensures the mock correctly implements method signatures, avoiding errors caused by incorrect argument types.
Seamless integration: Your tests will integrate with the actual system as expected without concerns for type mismatch. Method Mocking and Custom Behavior
Method Mocking and Custom Behavior
You can mock specific methods using closures that define the behavior you need for testing.
$mockFactory->mockMethod('methodName', fn($arg1, $arg2) => 'custom result'); // Call the method echo $mockObject->methodName($arg1, $arg2); // Outputs 'custom result'
Example Class
Here is a basic example class that demonstrates how to use the MockFactory
in different scenarios:
<?php use Zeus\Mock\MockFactory; interface Logger { public function log(string $message): void; } class LoggerService implements Logger { public function log(string $message): void { echo $message; } } class DatabaseService { private Logger $logger; public function __construct(Logger $logger) { $this->logger = $logger; } public function saveData(string $data): void { // Simulate saving data and logging the action $this->logger->log('Data saved: ' . $data); } } $mockFactory = new MockFactory(); // Create a mock Logger interface $mockLogger = $mockFactory->createMock(Logger::class); $mockFactory->mockMethod('log', fn($message) =>print 'mocked log: ' . $message); // Create a mock DatabaseService with the mocked Logger $mockDatabaseService = $mockFactory->createMock(DatabaseService::class,[ 'logger'=>new LoggerService() ]); // Use the service with mocked behavior $mockDatabaseService->saveData('Test Data'); // Outputs 'mocked log: Data saved: Test Data'
This example class shows how to create mocks for both interfaces and concrete classes, including the use of mocked methods,
type hinting, and checking instance types using instanceof
.
class Person { public function getName(): string { return 'Dilo surucu'; } } function get_name(PersonInterface $person): string { return $person->getName(); } $mockFactory = new MockFactory(); $mockPerson = $mockFactory->createMock(PersonInterface::class); $mockFactory->mockMethod('getName', function () { return 'Mocked Person'; }); echo get_name(new PersonInterface());//Dilo surucu echo get_name($mockPerson);//Mocked Person var_dump($mockPerson instanceof PersonInterface); //true
MockFactory - Mocking Interfaces Example
Overview
MockFactory is a powerful tool for mocking interfaces in PHP, allowing you to create mock instances and customize their behavior for unit testing. It ensures that mocked objects adhere to the expected type and guarantees compatibility with type hinting and instanceof
checks.
Example Usage - Mocking Interfaces
Example
use Zeus\Mock\MockFactory; interface PersonInterface { public function getName(): string; } $mockFactory = new MockFactory(); // Create a mock instance of PersonInterface $personService = $mockFactory->createMock(PersonInterface::class); // Mock the getName method $mockFactory->mockMethod('getName', fn(): string => 'dilo surucu'); function get_person(PersonInterface $person): string { return $person->getName(); } echo get_person($personService); // dilo surucu
Debug The code
There is a usage to see what kind of code the MockFactory class produces, this also allows you to debug it
interface MYInterface { public function foo():void; } $mockFactory = new MockFactory(); echo $mockFactory->generateCode(MYInterface::class,'CustomClassName'); /** class CustomClassName implements MYInterface { private object $mockFactory; public function __construct($mockFactory) { $this->mockFactory = $mockFactory; } public function foo():void { if ($this->mockFactory->hasMethodMock('foo')) { $this->mockFactory->invokeMockedMethod('foo', []); return; } throw new \Zeus\Mock\MockMethodNotFoundException('Method foo is not mocked.'); } }*/