Installation:
composer require --dev eloquent/phony-kahlan
Add to kahlan-config.php (if using dependency injection):
Kahlan\Filter\Filters::apply($this, 'run', function (callable $chain) {
Eloquent\Phony\Kahlan\install();
return $chain();
});
First Use Case: Mock a dependency in a test:
use function Eloquent\Phony\Kahlan\on;
describe('UserService', function (UserRepository $repo) {
it('creates a user', function (UserRepository $repo) {
on($repo)->save->with(new User())->returns(true);
expect($this->service->create())->toBe(true);
});
});
eloquent/phony-kahlan (source)Define Test Parameters:
describe('OrderService', function (OrderRepository $repo, Logger $logger) {
// $repo and $logger are auto-injected as mocks
});
Stub Interactions:
on($repo)->findById->with(1)->returns(new Order());
Verify Behavior:
on($repo)->findById->calledWith(1);
Mocking External APIs:
describe('PaymentProcessor', function (PaymentGateway $gateway) {
on($gateway)->charge->throws(new Exception('Failed'));
});
Stubbing Callables:
describe('EventDispatcher', function (callable $listener) {
$listener->with('event')->returns(true);
});
Type-Specific Defaults:
describe('DataTransformer', function (int $id, string $name) {
// $id = 0, $name = ''
});
Mock Eloquent Models:
describe('UserController', function (User $user) {
on($user)->save()->returns(true);
});
Stub Facades:
describe('AuthController', function (callable $auth) {
$auth->attempt()->returns(true);
});
Test Service Providers:
describe('AppServiceProvider', function (Container $container) {
on($container)->make('UserRepository')->returns($mockRepo);
});
PHP Version Mismatch:
Class 'Kahlan\Filter\Filters' not found → Ensure Kahlan 5.x is installed.Monkey-Patching Conflicts:
kahlan-config.php:
$this->commandLine()->set('exclude', ['Eloquent\Phony']);
Final Classes in Mocks:
final classes (e.g., DateTimeImmutable).emptyValue() or stub a wrapper class.Lazy Loading Issues:
Class not found, ensure Eloquent\Phony\Kahlan\install() runs after autoloading.Type Hinting Quirks:
object type hints receive an empty stdClass by default.on($obj) to access the mock handle.Verify Mocks:
on($mock)->method->called(); // Check if called
on($mock)->method->calledWith($args); // Check arguments
Inspect Stubbed Callables:
$stub = on($callable);
$stub->calledWith($args)->firstCall()->returned($value);
Reset Mocks Between Tests:
beforeEach(function () {
Eloquent\Phony\reset();
});
Custom Default Values:
Override Eloquent\Phony\Kahlan\emptyValue() in a service provider:
Eloquent\Phony\Kahlan\emptyValue('App\Models\User', fn() => new User());
Global Stubbing:
Pre-configure stubs in kahlan-config.php:
Eloquent\Phony\stub('App\Services\Logger')->log()->returns(true);
Custom Matchers: Extend Phony’s matchers for complex assertions:
Eloquent\Phony\matchers()->add('customMatcher', function ($actual, $expected) {
return $actual === $expected;
});
How can I help you explore Laravel packages today?